diff -Nru mlt-7.4.0/cmake/FindNDI.cmake mlt-7.6.0/cmake/FindNDI.cmake --- mlt-7.4.0/cmake/FindNDI.cmake 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/cmake/FindNDI.cmake 2022-04-19 08:45:41.000000000 +0000 @@ -2,7 +2,7 @@ set(NDI_SDK_LIBRARY_PATH "" CACHE PATH "NDI SDK library path") if(NOT (NDI_SDK_INCLUDE_PATH AND NDI_SDK_LIBRARY_PATH)) - message(FATAL_ERROR "NDI SDK: Please povide NDI_SDK_INCLUDE_PATH and NDI_SDK_LIBRARY_PATH!") + message(FATAL_ERROR "NDI SDK: Please provide NDI_SDK_INCLUDE_PATH and NDI_SDK_LIBRARY_PATH!") endif() find_path(NDI_INCLUDE_DIR @@ -50,4 +50,4 @@ mark_as_advanced( NDI_INCLUDE_DIR NDI_LIBRARY -) \ No newline at end of file +) diff -Nru mlt-7.4.0/CMakeLists.txt mlt-7.6.0/CMakeLists.txt --- mlt-7.4.0/CMakeLists.txt 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/CMakeLists.txt 2022-04-19 08:45:41.000000000 +0000 @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.14) project(MLT - VERSION 7.4.0 + VERSION 7.6.0 DESCRIPTION "Multimedia Framework" HOMEPAGE_URL "https://www.mltframework.org" LANGUAGES C CXX @@ -73,6 +73,17 @@ set(MLT_MODULE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/out/lib/mlt") set(MLT_DATA_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/out/share/mlt") +# https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/RPATH-handling +set(CMAKE_SKIP_BUILD_RPATH FALSE) +set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) +set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) +if(NOT "${isSystemDir}" STREQUAL "-1") + set(CMAKE_INSTALL_RPATH "") +endif() + + if(NOT EXISTS ${MLT_DATA_OUTPUT_DIRECTORY}) if(WIN32) # symlinks require admin rights on Windows file(COPY "${CMAKE_SOURCE_DIR}/src/modules" DESTINATION "${CMAKE_BINARY_DIR}/out/share" FILES_MATCHING REGEX yml|txt) @@ -91,12 +102,14 @@ endif() endif() -set(MLT_INSTALL_MODULE_DIR ${CMAKE_INSTALL_LIBDIR}/mlt) -set(MLT_INSTALL_DATA_DIR ${CMAKE_INSTALL_DATADIR}/mlt) +set(MLT_SUBDIR mlt) if(NOT (WIN32 OR APPLE)) - set(MLT_INSTALL_MODULE_DIR ${CMAKE_INSTALL_LIBDIR}/mlt-${MLT_VERSION_MAJOR}) - set(MLT_INSTALL_DATA_DIR ${CMAKE_INSTALL_DATADIR}/mlt-${MLT_VERSION_MAJOR}) + set(MLT_SUBDIR mlt-${MLT_VERSION_MAJOR}) + set(MLT_SUBDIR mlt-${MLT_VERSION_MAJOR}) endif() +set(MLT_INSTALL_MODULE_DIR ${CMAKE_INSTALL_LIBDIR}/${MLT_SUBDIR}) +set(MLT_INSTALL_DATA_DIR ${CMAKE_INSTALL_DATADIR}/${MLT_SUBDIR}) + set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) diff -Nru mlt-7.4.0/debian/changelog mlt-7.6.0/debian/changelog --- mlt-7.4.0/debian/changelog 2022-01-08 18:12:01.000000000 +0000 +++ mlt-7.6.0/debian/changelog 2022-04-19 08:45:42.000000000 +0000 @@ -1,8 +1,14 @@ -mlt (7.4.0-1~ubuntu20.04.1) focal; urgency=low +mlt (7.6.0-1~ubuntu20.04.1) focal; urgency=low * Auto build. - -- Vincent Pinon Sat, 08 Jan 2022 18:12:01 +0000 + -- Vincent Pinon Tue, 19 Apr 2022 08:45:42 +0000 + +mlt (7.5.0+git20220214-1) unstable; urgency=medium + + * pick CMake build system (new makefile is not for building) + + -- Vincent Pinon Mon, 14 Feb 2022 18:03:44 +0200 mlt (7.0.1-1) unstable; urgency=medium diff -Nru mlt-7.4.0/debian/git-build-recipe.manifest mlt-7.6.0/debian/git-build-recipe.manifest --- mlt-7.4.0/debian/git-build-recipe.manifest 2022-01-08 18:12:01.000000000 +0000 +++ mlt-7.6.0/debian/git-build-recipe.manifest 2022-04-19 08:45:42.000000000 +0000 @@ -1,3 +1,3 @@ -# git-build-recipe format 0.4 deb-version 7.4.0-1 -lp:~kdenlive/+git/mlt git-commit:255aa2452282bee3d7ec0c8320f9153f03d7e6c3 -merge packaging lp:~kdenlive/+git/mlt git-commit:63c62b18df78d0d17ab357e8856674948a77c997 +# git-build-recipe format 0.4 deb-version 7.6.0-1 +lp:~kdenlive/+git/mlt git-commit:576b4c7ab210c8edd1cbe04ad5b4d5f0b6c88cb6 +merge packaging lp:~kdenlive/+git/mlt git-commit:a4adb0fc760f16071b80f6db9ef7790b03a43674 diff -Nru mlt-7.4.0/debian/rules mlt-7.6.0/debian/rules --- mlt-7.4.0/debian/rules 2022-01-08 18:12:01.000000000 +0000 +++ mlt-7.6.0/debian/rules 2022-04-19 08:45:42.000000000 +0000 @@ -6,7 +6,7 @@ -DSWIG_PYTHON=ON %: - dh $@ --with python3 + dh $@ --buildsystem=cmake --with python3 override_dh_auto_configure: dh_auto_configure -- $(DEB_CONFIGURE_EXTRA_FLAGS) diff -Nru mlt-7.4.0/Dockerfile mlt-7.6.0/Dockerfile --- mlt-7.4.0/Dockerfile 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/Dockerfile 2022-04-19 08:45:41.000000000 +0000 @@ -21,14 +21,15 @@ echo "SOURCE_DIR=\"/tmp/melt\"" >> /tmp/build-melt.conf && \ echo "AUTO_APPEND_DATE=0" >> /tmp/build-melt.conf && \ echo "FFMPEG_HEAD=0" >> /tmp/build-melt.conf && \ - echo "FFMPEG_REVISION=origin/release/4.4" >> /tmp/build-melt.conf && \ + echo "FFMPEG_REVISION=origin/release/5.0" >> /tmp/build-melt.conf && \ bash /tmp/build-melt.sh -c /tmp/build-melt.conf FROM base # Install packages for running -RUN apt-get install -yqq libsamplerate0 libxml2 libjack0 \ +RUN apt-get install -yqq dumb-init \ + libsamplerate0 libxml2 libjack0 \ libsdl2-2.0-0 libgtk2.0-0 libsoup2.4-1 \ libqt5core5a libqt5gui5 libqt5opengl5 libqt5svg5 libqt5widgets5 \ libqt5x11extras5 libqt5xml5 libqt5webkit5 \ @@ -50,7 +51,5 @@ WORKDIR /mnt ENV LD_LIBRARY_PATH /usr/local/lib -# Qt, Movit, and WebVfx require xvfb-run -# IMPORTANT: xvfb-run requires docker run option "--init" -# https://docs.docker.com/engine/reference/commandline/run/ -ENTRYPOINT ["/usr/bin/xvfb-run", "-a", "/usr/local/bin/melt"] +# Qt, Movit, and WebVfx require xvfb-run, which requires a PID 1 init provided by dumb-init +ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/bin/xvfb-run", "-a", "/usr/local/bin/melt"] diff -Nru mlt-7.4.0/docs/melt.1 mlt-7.6.0/docs/melt.1 --- mlt-7.4.0/docs/melt.1 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/docs/melt.1 2022-04-19 08:45:41.000000000 +0000 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.4. -.TH MELT "1" "December 2021" "melt 7.4.0" "User Commands" +.TH MELT "1" "March 2022" "melt 7.6.0" "User Commands" .SH NAME melt \- author, play, and encode multitrack audio/video compositions .SH SYNOPSIS @@ -114,6 +114,9 @@ \fB\-serialise\fR [filename] Write the commands to a text file .TP +\fB\-setlocale\fR +Make numeric strings locale-sensitive (legacy support) +.TP \fB\-silent\fR Do not display position/transport .TP @@ -143,7 +146,7 @@ .PP For more help: .SH COPYRIGHT -Copyright \(co 2002\-2021 Meltytech, LLC +Copyright \(co 2002\-2022 Meltytech, LLC .br This is free software; see the source for copying conditions. There is NO diff -Nru mlt-7.4.0/Doxyfile mlt-7.6.0/Doxyfile --- mlt-7.4.0/Doxyfile 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/Doxyfile 2022-04-19 08:45:41.000000000 +0000 @@ -31,7 +31,7 @@ # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 7.4.0 +PROJECT_NUMBER = 7.6.0 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. diff -Nru mlt-7.4.0/.github/ISSUE_TEMPLATE.md mlt-7.6.0/.github/ISSUE_TEMPLATE.md --- mlt-7.4.0/.github/ISSUE_TEMPLATE.md 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/.github/ISSUE_TEMPLATE.md 2022-04-19 08:45:41.000000000 +0000 @@ -0,0 +1,4 @@ +This tracker is for defects only! For feature requests, you can submit a pull +request with the changes. + +If you’re reporting a defect, make it as detailed as possible, and include both your operating system and MLT versions (e.g. `macOS 10.16; MLT v7.4.0`). diff -Nru mlt-7.4.0/.gitlab-ci.yml mlt-7.6.0/.gitlab-ci.yml --- mlt-7.4.0/.gitlab-ci.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/.gitlab-ci.yml 2022-04-19 08:45:41.000000000 +0000 @@ -5,7 +5,7 @@ - DEBIAN_FRONTEND=noninteractive apt-get -qq update - DEBIAN_FRONTEND=noninteractive apt-get -yqq build-dep mlt - DEBIAN_FRONTEND=noninteractive apt-get -yqq install cmake - - cmake -DGPL=ON -DGPL3=ON . && make && make install + - cmake -DGPL=ON -DGPL3=ON . && make -j -f Makefile install # there's no `check` or `test` `make` target ubuntu-lts: @@ -15,7 +15,7 @@ - DEBIAN_FRONTEND=noninteractive apt-get -qq update - DEBIAN_FRONTEND=noninteractive apt-get -yqq build-dep mlt - DEBIAN_FRONTEND=noninteractive apt-get -yqq install cmake - - cmake -DGPL=ON -DGPL3=ON . && make && make install + - cmake -DGPL=ON -DGPL3=ON . && make -j -f Makefile install # there's no `check` or `test` `make` target debian-unstable: @@ -25,7 +25,7 @@ - apt-get -qq update - apt-get -yqq build-dep mlt - apt-get -yqq install cmake - - cmake -DGPL=ON -DGPL3=ON . && make && make install + - cmake -DGPL=ON -DGPL3=ON . && make -j -f Makefile install # there's no `check` or `test` `make` target debian-testing: @@ -35,7 +35,7 @@ - apt-get -qq update - apt-get -yqq build-dep mlt - apt-get -yqq install cmake - - cmake -DGPL=ON -DGPL3=ON . && make && make install + - cmake -DGPL=qON -DGPL3=ON . && make -j -f Makefile install # there's no `check` or `test` `make` target debian-stable: @@ -46,7 +46,7 @@ - apt-get -qq update - apt-get -yqq build-dep mlt - apt-get -yqq install cmake - - cmake -DGPL=ON -DGPL3=ON . && make && make install + - cmake -DGPL=ON -DGPL3=ON . && make -j -f Makefile install # there's no `check` or `test` `make` target fedora-33: @@ -55,7 +55,7 @@ - yum --assumeyes groupinstall "Development Tools" - yum --assumeyes install yasm gavl-devel libsamplerate-devel libxml2-devel ladspa-devel jack-audio-connection-kit-devel sox-devel SDL-devel gtk2-devel qt-devel libexif-devel libtheora-devel libvorbis-devel libvdpau-devel libsoup-devel liboil-devel python-devel alsa-lib pulseaudio-libs-devel gcc-c++ cmake # unclear why `gcc-c++` isn't in `Development Tools` - - cmake -DGPL=ON -DGPL3=ON . && make && make install + - cmake -DGPL=ON -DGPL3=ON . && make -j -f Makefile install fedora-32: image: fedora:32 @@ -63,7 +63,7 @@ - yum --assumeyes groupinstall "Development Tools" - yum --assumeyes install yasm gavl-devel libsamplerate-devel libxml2-devel ladspa-devel jack-audio-connection-kit-devel sox-devel SDL-devel gtk2-devel qt-devel libexif-devel libtheora-devel libvorbis-devel libvdpau-devel libsoup-devel liboil-devel python-devel alsa-lib pulseaudio-libs-devel gcc-c++ cmake # unclear why `gcc-c++` isn't in `Development Tools` - - cmake -DGPL=ON -DGPL3=ON . && make && make install + - cmake -DGPL=ON -DGPL3=ON . && make -j -f Makefile install fedora-31: image: fedora:31 @@ -71,7 +71,7 @@ - yum --assumeyes groupinstall "Development Tools" - yum --assumeyes install yasm gavl-devel libsamplerate-devel libxml2-devel ladspa-devel jack-audio-connection-kit-devel sox-devel SDL-devel gtk2-devel qt-devel libexif-devel libtheora-devel libvorbis-devel libvdpau-devel libsoup-devel liboil-devel python-devel alsa-lib pulseaudio-libs-devel gcc-c++ cmake # unclear why `gcc-c++` isn't in `Development Tools` - - cmake -DGPL=ON -DGPL3=ON . && make && make install + - cmake -DGPL=ON -DGPL3=ON . && make -j -f Makefile install fedora-30: image: fedora:30 @@ -79,4 +79,4 @@ - yum --assumeyes groupinstall "Development Tools" - yum --assumeyes install yasm gavl-devel libsamplerate-devel libxml2-devel ladspa-devel jack-audio-connection-kit-devel sox-devel SDL-devel gtk2-devel qt-devel libexif-devel libtheora-devel libvorbis-devel libvdpau-devel libsoup-devel liboil-devel python-devel alsa-lib pulseaudio-libs-devel gcc-c++ cmake # unclear why `gcc-c++` isn't in `Development Tools` - - cmake -DGPL=ON -DGPL3=ON . && make && make install + - cmake -DGPL=ON -DGPL3=ON . && make -j -f Makefile install diff -Nru mlt-7.4.0/makefile mlt-7.6.0/makefile --- mlt-7.4.0/makefile 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/makefile 2022-04-19 08:45:41.000000000 +0000 @@ -0,0 +1,17 @@ +default: + @echo This Makefile is not used for builing. Use CMake instead. + @echo Rather, this makefile is purely for holding some maintenance routines. + +dist: + git archive --format=tar --prefix=mlt-$(version)/ v$(version) | gzip >mlt-$(version).tar.gz + +validate-yml: + for file in $$(find src/modules -type f -name \*.yml \! -name resolution_scale.yml); do \ + echo "validate: $$file"; \ + kwalify -f src/framework/metaschema.yaml $$file || exit 1; \ + done + +codespell: + codespell -w -q 3 \ + -L shotcut,sav,boundry,percentil,readded,uint,ith,sinc,amin,childs,seeked,writen \ + -S ChangeLog,cJSON.c,cJSON.h,RtAudio.cpp,RtAudio.h,*.rej,mlt_wrap.* diff -Nru mlt-7.4.0/mlt-framework.pc.in mlt-7.6.0/mlt-framework.pc.in --- mlt-7.4.0/mlt-framework.pc.in 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/mlt-framework.pc.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ - -Name: mlt-framework -Description: MLT multimedia framework -Version: ${version} -Requires: -Libs: -L${libdir} ${libs} -Cflags: ${cflags} diff -Nru mlt-7.4.0/mlt++.pc.in mlt-7.6.0/mlt++.pc.in --- mlt-7.4.0/mlt++.pc.in 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/mlt++.pc.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ - -Name: mlt++ -Description: C++ API for MLT multimedia framework -Version: ${version} -Requires: mlt-framework -Libs: -L${libdir} ${libs} -Cflags: ${cflags} diff -Nru mlt-7.4.0/NEWS mlt-7.6.0/NEWS --- mlt-7.4.0/NEWS 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/NEWS 2022-04-19 08:45:41.000000000 +0000 @@ -1,9 +1,86 @@ MLT Release Notes ----------------- +Version 7.6.0 + +This version adds image slice-threading to many filters and full support for +full range color. All inputs are normalized to and processed at +the range specified by the consumer property `color_range` that defaults to +tv/mpeg (limited). + +Framework + * Added `Mlt::Animation::next_key()` and `previous_key()` with error checking. + * Fixed the `moduledir` and `mltdatadir` variables in the pkg-config file. + * Removed calling `setlocale()` in `mlt_factory_init()` (moved to `melt` + option `-setlocale`). + * Added `mlt_properties_copy()` and `Mlt::Properties::copy()`. + * Changed some primarily internal property names to consolidate on "consumer." + as a prefix convention for all consumer properties copied to `mlt_frame`s. + * Added consumer property `deinterlacer` to replace deprecated `deinterlace_method`. + * Fixed full range color from producer to consumer. + * Added `mlt_slices_size_slice()` helper function. + * Fixed choppy playback due to large values in `frame_rate_num` or + `frame_rate_den` in `mlt_consumer`. + * Added performance optimization for a single slice in `mlt_slices`. + +Modules + * Added `audiolevelgraph` video filter to the `qt` module. + * Added property `segment_gap` to the `audiospectrum` video filter. + * Added `segments` property to the `audiolevelgraph` and `audiospectrum` filters. + * Fixed loading image sequence with extended UTF-8 characters in the + name of a folder for the `qimage` producer. + * Fixed a crash in `avformat` producer if the `rotate` property is set after + the first frame is fetched. + * Added the `invert_mask` property to the `shape` video filter. + * Changed `avformat` producer to normalize frame rates very close to + non-integer broadcast frames 24/1.001, 30/1.001, and 60/1.001. + * Converted the `chroma` and `chroma_hold` filters' `key` property to a proper + color type. + * Added slice threading to: + - `avformat` producer (with FFmpeg v5) + - `swsscale` (with FFmpeg v5) + - `lift_gamma_gain` + - `shape` + - `charcoal` + - `vignette` + - `wave` + - `threshold` + - `tcolor` + - `sepia` + - `mirror` + - `invert` + - `grain` + - `lines` + - `spot_remover` + * Improved the speed of the `oldfilm` filter. + * Added a faster `box_blur` filter to the core module and deprecated the + `boxblur` filter in the kdenlive module. + * Fixed preview scaling for the `avfilter.gblur` filter. + * Fixed incorrect text overlap in `kdenlivetitle` producer. + * Improved audio synchronization in `avformat` when playing in reverse. + * Added much more service metadata (documentation). + * Fixed full range 10-bit video input in `avformat` producer. + * Fixed full range color handling in: + - `avformat` producer + - `avcolor_space` + - `brightness` + - `resize` + - `luma` transition + - `movit.convert` + - `charcoal` + - `invert` + - `shape` + * Fixed identifying unsupported colorspaces in `avformat` producer. + * Fixed preserving the alpha channel in the `avfilter.fspp` filter. + +Other + - Some CMake fixes. + - Added `dumb-init` to the docker (no need to remember `docker run --init`). + + Version 7.4.0 -This main highlight of this version is property animation for avfilter! +The main highlight of this version is property animation for avfilter! Framework * Added more constructors and assignment operators in C++ wrapper: diff -Nru mlt-7.4.0/src/framework/mlt_animation.c mlt-7.6.0/src/framework/mlt_animation.c --- mlt-7.4.0/src/framework/mlt_animation.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_animation.c 2022-04-19 08:45:42.000000000 +0000 @@ -603,6 +603,9 @@ while ( node && node->next && position >= node->next->item.frame ) node = node->next; + if ( position < node->item.frame ) + node = NULL; + if ( node ) { item->frame = node->item.frame; diff -Nru mlt-7.4.0/src/framework/mlt_consumer.c mlt-7.6.0/src/framework/mlt_consumer.c --- mlt-7.4.0/src/framework/mlt_consumer.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_consumer.c 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief abstraction for all consumer services * \see mlt_consumer_s * - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -540,7 +540,7 @@ if ( frame_rate_num && frame_rate_den ) { - frame_duration = 1000000 / frame_rate_num * frame_rate_den; + frame_duration = 1000000.0 / frame_rate_num * frame_rate_den; } mlt_properties_set_int( properties, "frame_duration", frame_duration ); @@ -688,12 +688,13 @@ // Pass along the interpolation and deinterlace options // TODO: get rid of consumer_deinterlace and use profile.progressive - mlt_properties_set( frame_properties, "rescale.interp", mlt_properties_get( properties, "rescale" ) ); - mlt_properties_set_int( frame_properties, "consumer_deinterlace", mlt_properties_get_int( properties, "progressive" ) | mlt_properties_get_int( properties, "deinterlace" ) ); - mlt_properties_set( frame_properties, "deinterlace_method", mlt_properties_get( properties, "deinterlace_method" ) ); - mlt_properties_set_int( frame_properties, "consumer_tff", mlt_properties_get_int( properties, "top_field_first" ) ); - mlt_properties_set( frame_properties, "consumer_color_trc", mlt_properties_get( properties, "color_trc" ) ); - mlt_properties_set( frame_properties, "consumer_channel_layout", mlt_properties_get( properties, "channel_layout" ) ); + mlt_properties_set( frame_properties, "consumer.rescale", mlt_properties_get( properties, "rescale" ) ); + mlt_properties_set_int( frame_properties, "consumer.progressive", mlt_properties_get_int( properties, "progressive" ) | mlt_properties_get_int( properties, "deinterlace" ) ); + mlt_properties_set( frame_properties, "consumer.deinterlacer", mlt_properties_get(properties, "deinterlacer")? mlt_properties_get(properties, "deinterlacer") : mlt_properties_get(properties, "deinterlace_method") ); + mlt_properties_set_int( frame_properties, "consumer.top_field_first", mlt_properties_get_int( properties, "top_field_first" ) ); + mlt_properties_set( frame_properties, "consumer.color_trc", mlt_properties_get( properties, "color_trc" ) ); + mlt_properties_set( frame_properties, "consumer.channel_layout", mlt_properties_get( properties, "channel_layout" ) ); + mlt_properties_set( frame_properties, "consumer.color_range", mlt_properties_get( properties, "color_range" ) ); } // Return the frame @@ -852,7 +853,7 @@ if ( priv->speed != 1 ) { #ifdef DEINTERLACE_ON_NOT_NORMAL_SPEED - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer.progressive", 1 ); #endif // Indicate seeking or trick-play start_pos = pos; @@ -1052,7 +1053,7 @@ #ifdef DEINTERLACE_ON_NOT_NORMAL_SPEED // All non normal playback frames should be shown if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "_speed" ) != 1 ) - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer.progressive", 1 ); #endif // Get the image diff -Nru mlt-7.4.0/src/framework/mlt_consumer.h mlt-7.6.0/src/framework/mlt_consumer.h --- mlt-7.4.0/src/framework/mlt_consumer.h 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_consumer.h 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief abstraction for all consumer services * \see mlt_consumer_s * - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -85,6 +85,9 @@ * \properties \em audio_off set non-zero to disable audio processing * \properties \em video_off set non-zero to disable video processing * \properties \em drop_count the number of video frames not rendered since starting consumer + * \properties \em color_range the color range as tv/mpeg (limited) or pc/jpeg (full); default is unset, which implies tv/mpeg + * \properties \em color_trc the color transfer characteristic (gamma), default is unset + * \properties \em deinterlacer the deinterlace algorithm to pass to deinterlace filters, defaults to "yadif" */ struct mlt_consumer_s diff -Nru mlt-7.4.0/src/framework/mlt_factory.c mlt-7.6.0/src/framework/mlt_factory.c --- mlt-7.4.0/src/framework/mlt_factory.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_factory.c 2022-04-19 08:45:42.000000000 +0000 @@ -2,7 +2,7 @@ * \file mlt_factory.c * \brief the factory method interfaces * - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,7 +25,6 @@ #include #include #include -#include #include /** the default subdirectory of the datadir for holding presets */ @@ -112,14 +111,6 @@ mlt_repository mlt_factory_init( const char *directory ) { - // Load the system locales - const char* locale = ""; -#if defined(_WIN32) - if (getenv("LC_ALL")) - locale = getenv("LC_ALL"); -#endif - setlocale( LC_ALL, locale ); - if ( ! global_properties ) global_properties = mlt_properties_new( ); diff -Nru mlt-7.4.0/src/framework/mlt_frame.c mlt-7.6.0/src/framework/mlt_frame.c --- mlt-7.4.0/src/framework/mlt_frame.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_frame.c 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief interface for all frame classes * \see mlt_frame_s * - * Copyright (C) 2003-2019 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -404,7 +404,7 @@ { mlt_properties test_properties = MLT_FRAME_PROPERTIES( test_frame ); mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); - mlt_properties_set( test_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) ); + mlt_properties_set( test_properties, "consumer.rescale", mlt_properties_get( properties, "consumer.rescale" ) ); error = mlt_frame_get_image( test_frame, buffer, format, width, height, writable ); if ( !error && buffer && *buffer ) { diff -Nru mlt-7.4.0/src/framework/mlt_frame.h mlt-7.6.0/src/framework/mlt_frame.h --- mlt-7.4.0/src/framework/mlt_frame.h 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_frame.h 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief interface for all frame classes * \see mlt_frame_s * - * Copyright (C) 2003-2018 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -59,7 +59,7 @@ * \properties \em next \em frame a reference to the unfiltered following frame * (no speed factor applied, only available when \em _need_previous_next is set on the producer) * \properties \em colorspace the standard for the YUV coefficients - * \properties \em force_full_luma luma range handling, set to -1 for pass-through, 1 for full range, 0 for scaling + * \properties \em force_full_luma luma range handling: 1 for full range, 0 for scaling (DEPRECATED) * \properties \em color_trc the color transfer characteristic (gamma) * \properties \em audio_frequency the sample rate of the audio * \properties \em audio_channels the number of audio channels @@ -69,6 +69,7 @@ * \properties \em width the horizontal resolution of the image * \properties \em height the vertical resolution of the image * \properties \em aspect_ratio the sample aspect ratio of the image + * \properties \em full_range set if the video is full range - only applies to Y'CbCr */ struct mlt_frame_s diff -Nru mlt-7.4.0/src/framework/mlt-framework.pc.in mlt-7.6.0/src/framework/mlt-framework.pc.in --- mlt-7.4.0/src/framework/mlt-framework.pc.in 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt-framework.pc.in 2022-04-19 08:45:42.000000000 +0000 @@ -4,8 +4,8 @@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ datadir=@CMAKE_INSTALL_FULL_DATADIR@ -moduledir=${libdir}/mlt-@MLT_VERSION_MAJOR@ -mltdatadir=${datadir}/mlt-@MLT_VERSION_MAJOR@ +moduledir=${prefix}/@MLT_INSTALL_MODULE_DIR@ +mltdatadir=${datadir}/@MLT_SUBDIR@ Name: mlt-framework Description: MLT multimedia framework diff -Nru mlt-7.4.0/src/framework/mlt_image.c mlt-7.6.0/src/framework/mlt_image.c --- mlt-7.4.0/src/framework/mlt_image.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_image.c 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief Image class * \see mlt_mlt_image_s * - * Copyright (C) 2020-2021 Meltytech, LLC + * Copyright (C) 2020-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -364,7 +364,7 @@ if ( bpp ) *bpp = 0; return 4; case mlt_image_yuv422p16: - if ( bpp ) *bpp = 0; + if ( bpp ) *bpp = 4; return 4 * height * width ; default: if ( bpp ) *bpp = 0; @@ -408,22 +408,18 @@ strides[3] = 0; planes[0] = (unsigned char*)data; - planes[1] = (unsigned char*)data + width * height; - planes[2] = (unsigned char*)data + ( 5 * width * height ) / 4; + planes[1] = planes[0] + width * height; + planes[2] = planes[1] + (width >> 1) + (height >> 1); planes[3] = 0; } else { - int bpp; - - mlt_image_format_size( format, width, height, &bpp ); - planes[0] = data; planes[1] = 0; planes[2] = 0; planes[3] = 0; - strides[0] = bpp * width; + strides[0] = mlt_image_format_size( format, width, 1, NULL ); strides[1] = 0; strides[2] = 0; strides[3] = 0; diff -Nru mlt-7.4.0/src/framework/mlt_playlist.c mlt-7.6.0/src/framework/mlt_playlist.c --- mlt-7.4.0/src/framework/mlt_playlist.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_playlist.c 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief playlist service class * \see mlt_playlist_s * - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1078,12 +1078,7 @@ mlt_properties split_properties = MLT_PRODUCER_PROPERTIES( split ); mlt_playlist_insert( self, split, clip + 1, 0, -1 ); mlt_properties_lock( entry_properties ); - for ( i = 0; i < mlt_properties_count( entry_properties ); i ++ ) - { - char *name = mlt_properties_get_name( entry_properties, i ); - if ( name != NULL && !strncmp( name, "meta.", 5 ) ) - mlt_properties_set( split_properties, name, mlt_properties_get_value( entry_properties, i ) ); - } + mlt_properties_copy(split_properties, entry_properties, "meta."); mlt_properties_unlock( entry_properties ); mlt_producer_close( split ); } @@ -2087,7 +2082,7 @@ // Set the consumer progressive property if ( progressive ) { - mlt_properties_set_int( properties, "consumer_deinterlace", progressive ); + mlt_properties_set_int( properties, "consumer.progressive", progressive ); mlt_properties_set_int( properties, "test_audio", 1 ); } diff -Nru mlt-7.4.0/src/framework/mlt_playlist.h mlt-7.6.0/src/framework/mlt_playlist.h --- mlt-7.4.0/src/framework/mlt_playlist.h 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_playlist.h 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief playlist service class * \see mlt_playlist_s * - * Copyright (C) 2003-2014 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -59,7 +59,7 @@ * \properties \em autoclose Set this true if you are doing sequential processing and want to * automatically close producers as they are finished being used to free resources. * \properties \em meta.fx_cut Set true on a producer to indicate that it is a "fx_cut," - * which is a way to add filters as a playlist entry - useful only in a multitrack. See FxCut on the wiki. + * which is a way to add filters as a playlist entry - useful only in a multitrack. See FxCut in the docs. * \properties \em mix_in * \properties \em mix_out * \properties \em hide Set to 1 to hide the video (make it an audio-only track), diff -Nru mlt-7.4.0/src/framework/mlt_producer.c mlt-7.6.0/src/framework/mlt_producer.c --- mlt-7.4.0/src/framework/mlt_producer.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_producer.c 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief abstraction for all producer services * \see mlt_producer_s * - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -732,19 +732,11 @@ // Pass on all meta properties from the producer/cut on to the frame if ( *frame != NULL && self != NULL ) { - int i = 0; mlt_properties p_props = MLT_PRODUCER_PROPERTIES( self ); mlt_properties f_props = MLT_FRAME_PROPERTIES( *frame ); mlt_properties_lock( p_props ); - int count = mlt_properties_count( p_props ); - for ( i = 0; i < count; i ++ ) - { - char *name = mlt_properties_get_name( p_props, i ); - if ( !strncmp( name, "meta.", 5 ) ) - mlt_properties_set( f_props, name, mlt_properties_get_value( p_props, i ) ); - else if ( !strncmp( name, "set.", 4 ) ) - mlt_properties_set( f_props, name + 4, mlt_properties_get_value( p_props, i ) ); - } + mlt_properties_copy(f_props, p_props, "meta."); + mlt_properties_pass(f_props, p_props, "set."); mlt_properties_unlock( p_props ); } diff -Nru mlt-7.4.0/src/framework/mlt_profile.c mlt-7.6.0/src/framework/mlt_profile.c --- mlt-7.4.0/src/framework/mlt_profile.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_profile.c 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief video output definition * \see mlt_profile_s * - * Copyright (C) 2007-2018 Meltytech, LLC + * Copyright (C) 2007-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -414,7 +414,7 @@ if ( ! mlt_service_get_frame( MLT_PRODUCER_SERVICE(producer), &fr, 0 ) && fr ) { // Skip scaling and padding since not needed and we request mlt_image_none. - mlt_properties_set( MLT_FRAME_PROPERTIES(fr), "rescale.interp", "none" ); + mlt_properties_set( MLT_FRAME_PROPERTIES(fr), "consumer.rescale", "none" ); if ( ! mlt_frame_get_image( fr, &buffer, &fmt, &w, &h, 0 ) ) { diff -Nru mlt-7.4.0/src/framework/mlt_properties.c mlt-7.6.0/src/framework/mlt_properties.c --- mlt-7.4.0/src/framework/mlt_properties.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_properties.c 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief Properties class definition * \see mlt_properties_s * - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -487,6 +487,34 @@ return 0; } +/** Copy all serializable properties that match a prefix to another properties object + * + * \public \memberof mlt_properties_s + * \param self the properties to copy to + * \param that The properties to copy from + * \param prefix the property names to match (required) + * \return true if error + */ + +int mlt_properties_copy( mlt_properties self, mlt_properties that, const char *prefix ) +{ + if ( !self || !that ) return 1; + int count = mlt_properties_count( that ); + int length = strlen( prefix ); + int i = 0; + for ( i = 0; i < count; i ++ ) + { + char *name = mlt_properties_get_name( that, i ); + if ( !strncmp( name, prefix, length ) ) + { + char *value = mlt_properties_get_value( that, i ); + if ( value != NULL ) + mlt_properties_set_string( self, name, value ); + } + } + return 0; +} + /** Pass all serializable properties that match a prefix to another properties object * * \warning The prefix is stripped from the name when it is set on the \p self properties list! diff -Nru mlt-7.4.0/src/framework/mlt_properties.h mlt-7.6.0/src/framework/mlt_properties.h --- mlt-7.4.0/src/framework/mlt_properties.h 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_properties.h 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief Properties class declaration * \see mlt_properties_s * - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -57,6 +57,7 @@ extern int mlt_properties_ref_count( mlt_properties self ); extern void mlt_properties_mirror( mlt_properties self, mlt_properties that ); extern int mlt_properties_inherit( mlt_properties self, mlt_properties that ); +extern int mlt_properties_copy( mlt_properties self, mlt_properties that, const char *prefix ); extern int mlt_properties_pass( mlt_properties self, mlt_properties that, const char *prefix ); extern void mlt_properties_pass_property( mlt_properties self, mlt_properties that, const char *name ); extern int mlt_properties_pass_list( mlt_properties self, mlt_properties that, const char *list ); diff -Nru mlt-7.4.0/src/framework/mlt_slices.c mlt-7.6.0/src/framework/mlt_slices.c --- mlt-7.4.0/src/framework/mlt_slices.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_slices.c 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief sliced threading processing helper * \see mlt_slices_s * - * Copyright (C) 2016-2021 Meltytech, LLC + * Copyright (C) 2016-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -265,11 +265,17 @@ * \private \memberof mlt_slices_s * \param ctx context pointer * \param jobs number of jobs to process - * \param proc number of jobs to process + * \param proc a pointer to the function that will be called + * \param cookie an opaque data pointer passed to \p proc */ static void mlt_slices_run( mlt_slices ctx, int jobs, mlt_slices_proc proc, void* cookie ) { + if ( jobs == 1 ) + { + proc(0, 0, 1, cookie); + return; + } struct mlt_slices_runtime_s runtime, *r = &runtime; /* lock */ @@ -408,3 +414,27 @@ return mlt_slices_run( mlt_slices_get_global( mlt_policy_fifo ), jobs, proc, cookie ); } + + +/** Compute size of a slice. + * + * This a helper function for use in a mlt_slices_proc() to get the number of + * pixels over which to operate. + * + * \public \memberof mlt_slices_s + * \param jobs the number of slices + * \param index the zero-based index of the current slice + * \param input_size the size of a dimension, usually in pixel units, for example height + * \param[out] start the optional starting unit for this slice + * \return the size of the slice, typically in pixel units + */ + +int mlt_slices_size_slice(int jobs, int index, int input_size, int *start) +{ + int size = (input_size + jobs - 1) / jobs; + int my_start = index * size; + if (start) { + *start = my_start; + } + return CLAMP(input_size - my_start, 0, size); +} diff -Nru mlt-7.4.0/src/framework/mlt_slices.h mlt-7.6.0/src/framework/mlt_slices.h --- mlt-7.4.0/src/framework/mlt_slices.h 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_slices.h 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief sliced threading processing helper * \see mlt_slices_s * - * Copyright (C) 2016-2021 Meltytech, LLC + * Copyright (C) 2016-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -46,4 +46,6 @@ extern void mlt_slices_run_fifo( int jobs, mlt_slices_proc proc, void* cookie ); +extern int mlt_slices_size_slice(int jobs, int index, int input_size, int *start); + #endif diff -Nru mlt-7.4.0/src/framework/mlt_tractor.c mlt-7.6.0/src/framework/mlt_tractor.c --- mlt-7.4.0/src/framework/mlt_tractor.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_tractor.c 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief tractor service class * \see mlt_tractor_s * - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -358,13 +358,10 @@ mlt_properties properties = MLT_FRAME_PROPERTIES( self ); mlt_frame frame = mlt_frame_pop_service( self ); mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); - mlt_properties_set( frame_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) ); + mlt_properties_set_int( frame_properties, "resize_alpha", mlt_properties_get_int( properties, "resize_alpha" ) ); mlt_properties_set_int( frame_properties, "distort", mlt_properties_get_int( properties, "distort" ) ); - mlt_properties_set_int( frame_properties, "consumer_deinterlace", mlt_properties_get_int( properties, "consumer_deinterlace" ) ); - mlt_properties_set( frame_properties, "deinterlace_method", mlt_properties_get( properties, "deinterlace_method" ) ); - mlt_properties_set_int( frame_properties, "consumer_tff", mlt_properties_get_int( properties, "consumer_tff" ) ); - mlt_properties_set( frame_properties, "consumer_color_trc", mlt_properties_get( properties, "consumer_color_trc" ) ); + mlt_properties_copy(frame_properties, properties, "consumer."); // WebVfx uses this to setup a consumer-stopping event handler. mlt_properties_set_data( frame_properties, "consumer", mlt_properties_get_data( properties, "consumer", NULL ), 0, NULL, NULL ); @@ -378,7 +375,7 @@ mlt_properties_set_int( properties, "progressive", mlt_properties_get_int( frame_properties, "progressive" ) ); mlt_properties_set_int( properties, "distort", mlt_properties_get_int( frame_properties, "distort" ) ); mlt_properties_set_int( properties, "colorspace", mlt_properties_get_int( frame_properties, "colorspace" ) ); - mlt_properties_set_int( properties, "full_luma", mlt_properties_get_int( frame_properties, "full_luma" ) ); + mlt_properties_set_int( properties, "full_range", mlt_properties_get_int( frame_properties, "full_range" ) ); mlt_properties_set_int( properties, "force_full_luma", mlt_properties_get_int( frame_properties, "force_full_luma" ) ); mlt_properties_set_int( properties, "top_field_first", mlt_properties_get_int( frame_properties, "top_field_first" ) ); mlt_properties_set( properties, "color_trc", mlt_properties_get( frame_properties, "color_trc" ) ); @@ -416,7 +413,7 @@ mlt_properties properties = MLT_FRAME_PROPERTIES( self ); mlt_frame frame = mlt_frame_pop_audio( self ); mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); - mlt_properties_set( frame_properties, "consumer_channel_layout", mlt_properties_get( properties, "consumer_channel_layout" ) ); + mlt_properties_set( frame_properties, "consumer.channel_layout", mlt_properties_get( properties, "consumer.channel_layout" ) ); mlt_properties_set( frame_properties, "producer_consumer_fps", mlt_properties_get( properties, "producer_consumer_fps" ) ); mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); mlt_frame_set_audio( self, *buffer, *format, mlt_audio_format_size( *format, *samples, *channels ), NULL ); @@ -503,14 +500,7 @@ // Pass all unique meta properties from the producer's frame to the new frame mlt_properties_lock( temp_properties ); - int props_count = mlt_properties_count( temp_properties ); - int j; - for ( j = 0; j < props_count; j ++ ) - { - char *name = mlt_properties_get_name( temp_properties, j ); - if ( !strncmp( name, "meta.", 5 ) && !mlt_properties_get( frame_properties, name ) ) - mlt_properties_set( frame_properties, name, mlt_properties_get_value( temp_properties, j ) ); - } + mlt_properties_copy(frame_properties, temp_properties, "meta."); mlt_properties_unlock( temp_properties ); // Copy the format conversion virtual functions diff -Nru mlt-7.4.0/src/framework/mlt_transition.c mlt-7.6.0/src/framework/mlt_transition.c --- mlt-7.4.0/src/framework/mlt_transition.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_transition.c 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,7 @@ * \brief abstraction for all transition services * \see mlt_transition_s * - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -333,9 +333,9 @@ mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); // All transitions get scaling - const char *rescale = mlt_properties_get( a_props, "rescale.interp" ); + const char *rescale = mlt_properties_get( a_props, "consumer.rescale" ); if ( !rescale || !strcmp( rescale, "none" ) ) - mlt_properties_set( a_props, "rescale.interp", "nearest" ); + mlt_properties_set( a_props, "consumer.rescale", "nearest" ); // Ensure sane aspect ratio if ( mlt_frame_get_aspect_ratio( a_frame ) == 0.0 ) @@ -352,20 +352,19 @@ mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); // Set scaling from A frame if not already provided. - if ( !mlt_properties_get( b_props, "rescale.interp" ) ) + if ( !mlt_properties_get( b_props, "consumer.rescale" ) ) { - const char *rescale = mlt_properties_get( a_props, "rescale.interp" ); + const char *rescale = mlt_properties_get( a_props, "consumer.rescale" ); if ( !rescale || !strcmp( rescale, "none" ) ) rescale = "nearest"; - mlt_properties_set( b_props, "rescale.interp", rescale ); + mlt_properties_set( b_props, "consumer.rescale", rescale ); } // Ensure sane aspect ratio if ( mlt_frame_get_aspect_ratio( b_frame ) == 0.0 ) mlt_frame_set_aspect_ratio( b_frame, mlt_profile_sar( mlt_service_profile( MLT_TRANSITION_SERVICE(self) ) ) ); - mlt_properties_pass_list( b_props, a_props, - "consumer_deinterlace, deinterlace_method, consumer_tff, consumer_color_trc, consumer_channel_layout" ); + mlt_properties_copy(b_props, a_props, "consumer."); return mlt_frame_get_image( b_frame, image, format, width, height, writable ); } diff -Nru mlt-7.4.0/src/framework/mlt.vers mlt-7.6.0/src/framework/mlt.vers --- mlt-7.4.0/src/framework/mlt.vers 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt.vers 2022-04-19 08:45:42.000000000 +0000 @@ -630,3 +630,9 @@ mlt_property_is_anim; mlt_properties_is_anim; } MLT_7.1.0; + +MLT_7.6.0 { + global: + mlt_properties_copy; + mlt_slices_size_slice; +} MLT_7.4.0; diff -Nru mlt-7.4.0/src/framework/mlt_version.h mlt-7.6.0/src/framework/mlt_version.h --- mlt-7.4.0/src/framework/mlt_version.h 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/framework/mlt_version.h 2022-04-19 08:45:42.000000000 +0000 @@ -2,7 +2,7 @@ * \file mlt_version.h * \brief contains version information * - * Copyright (C) 2010-2021 Meltytech, LLC + * Copyright (C) 2010-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,7 +27,7 @@ #define MLT_STRINGIZE(s) MLT_STRINGIZE2(s) #define LIBMLT_VERSION_MAJOR 7 -#define LIBMLT_VERSION_MINOR 4 +#define LIBMLT_VERSION_MINOR 6 #define LIBMLT_VERSION_REVISION 0 #define LIBMLT_VERSION_INT ((LIBMLT_VERSION_MAJOR<<16)+(LIBMLT_VERSION_MINOR<<8)+LIBMLT_VERSION_REVISION) #define LIBMLT_VERSION MLT_STRINGIZE(LIBMLT_VERSION_MAJOR.LIBMLT_VERSION_MINOR.LIBMLT_VERSION_REVISION) diff -Nru mlt-7.4.0/src/melt/CMakeLists.txt mlt-7.6.0/src/melt/CMakeLists.txt --- mlt-7.4.0/src/melt/CMakeLists.txt 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/melt/CMakeLists.txt 2022-04-19 08:45:42.000000000 +0000 @@ -18,10 +18,11 @@ target_link_options(melt PRIVATE -mconsole) endif() -if(WIN32 OR APPLE) - install(TARGETS melt RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -else() - install(PROGRAMS "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/melt" DESTINATION ${CMAKE_INSTALL_BINDIR} RENAME melt-${MLT_VERSION_MAJOR}) +install(TARGETS melt RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +if(UNIX AND NOT APPLE) + install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E rename melt melt-${MLT_VERSION_MAJOR} \ + WORKING_DIRECTORY \$ENV\{DESTDIR\}${CMAKE_INSTALL_FULL_BINDIR})" + ) install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink melt-${MLT_VERSION_MAJOR} melt \ WORKING_DIRECTORY \$ENV\{DESTDIR\}${CMAKE_INSTALL_FULL_BINDIR})" ) diff -Nru mlt-7.4.0/src/melt/melt.c mlt-7.6.0/src/melt/melt.c --- mlt-7.4.0/src/melt/melt.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/melt/melt.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * melt.c -- MLT command line utility - * Copyright (C) 2002-2021 Meltytech, LLC + * Copyright (C) 2002-2022 Meltytech, LLC * * 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 @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -532,6 +533,7 @@ " -repeat times Repeat the last cut\n" " -repository path Set the directory of MLT modules\n" " -serialise [filename] Write the commands to a text file\n" +" -setlocale Make numeric strings locale-sensitive\n" " -silent Do not display position/transport\n" " -split relative-frame Split the last cut into two cuts\n" " -swap Rearrange the last two cuts\n" @@ -751,6 +753,21 @@ } } +static mlt_repository setup_factory(const char* repo_path, int set_locale) +{ + mlt_repository repo = mlt_factory_init(repo_path); + if (repo && set_locale) { + // Load the system locales + const char* locale = ""; +#if defined(_WIN32) + if (getenv("LC_ALL")) + locale = getenv("LC_ALL"); +#endif + setlocale( LC_ALL, locale ); + } + return repo; +} + int main( int argc, char **argv ) { int i; @@ -767,12 +784,20 @@ mlt_repository repo = NULL; const char* repo_path = NULL; int is_consumer_explicit = 0; + int is_setlocale = 0; // Handle abnormal exit situations. signal( SIGSEGV, abnormal_exit_handler ); signal( SIGILL, abnormal_exit_handler ); signal( SIGABRT, abnormal_exit_handler ); + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-setlocale")) { + is_setlocale = 1; + break; + } + } + for ( i = 1; i < argc; i ++ ) { // Check for serialisation switch @@ -793,7 +818,7 @@ { // Construct the factory if ( !repo ) - repo = mlt_factory_init( repo_path ); + repo = setup_factory(repo_path, is_setlocale); const char *pname = argv[ ++ i ]; if ( pname && pname[0] != '-' ) @@ -812,8 +837,8 @@ { // Construct the factory if ( !repo ) - repo = mlt_factory_init( repo_path ); - + repo = setup_factory(repo_path, is_setlocale); + const char *pname = argv[ ++ i ]; if ( pname && pname[0] != '-' ) { @@ -884,7 +909,7 @@ else if ( !strcmp( argv[ i ], "-version" ) || !strcmp( argv[ i ], "--version" ) ) { fprintf( stdout, "%s " VERSION "\n" - "Copyright (C) 2002-2021 Meltytech, LLC\n" + "Copyright (C) 2002-2022 Meltytech, LLC\n" "\n" "This is free software; see the source for copying conditions. There is NO\n" "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", @@ -918,7 +943,7 @@ // Construct the factory if ( !repo ) - repo = mlt_factory_init( repo_path ); + repo = setup_factory(repo_path, is_setlocale); // Create profile if not set explicitly if ( getenv( "MLT_PROFILE" ) ) diff -Nru mlt-7.4.0/src/mlt++/MltAnimation.cpp mlt-7.6.0/src/mlt++/MltAnimation.cpp --- mlt-7.4.0/src/mlt++/MltAnimation.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/mlt++/MltAnimation.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /** * MltAnimation.cpp - MLT Wrapper - * Copyright (C) 2015-2018 Meltytech, LLC + * Copyright (C) 2015-2021 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -101,6 +101,15 @@ return (mlt_keyframe_type) -1; } +/** Get the keyfame at the position or the next following. + * + * If no keyframe exists at or after the position, the return value is invalid + * + * \deprecated Prefer bool Animation::next_key( int position, int& key ) + * \param position the frame number at which to start looking for the next keyframe + * \return the position of the next keyframe + */ + int Animation::next_key( int position ) { struct mlt_animation_item_s item; @@ -112,6 +121,36 @@ return error; } +/** Get the keyfame at the position or the next following. + * + * On error, key is not modified. + * + * \param position the frame number at which to start looking for the next keyframe + * \param key the returned position of the next keyframe + * \return true if there was an error + */ + +bool Animation::next_key( int position, int& key ) +{ + struct mlt_animation_item_s item; + item.property = NULL; + bool error = mlt_animation_next_key( instance, &item, position ); + if ( !error ) + { + key = item.frame; + } + return error; +} + +/** Get the keyfame at the position or the previous keyframe before. + * + * If no keyframe exists at or before the position, the return value is invalid + * + * \deprecated Prefer bool Animation::previous_key( int position, int& key ) + * \param position the frame number at which to start looking for the previous keyframe + * \return the position of the previous keyframe + */ + int Animation::previous_key( int position ) { struct mlt_animation_item_s item; @@ -123,6 +162,27 @@ return error; } +/** Get the keyfame at the position or the previous before. + * + * On error, key is not modified. + * + * \param position the frame number at which to start looking for the previous keyframe + * \param key the returned position of the previous keyframe + * \return true if there was an error + */ + +bool Animation::previous_key( int position, int& key ) +{ + struct mlt_animation_item_s item; + item.property = NULL; + bool error = mlt_animation_prev_key( instance, &item, position ); + if ( !error ) + { + key = item.frame; + } + return error; +} + int Animation::key_count() { return mlt_animation_key_count( instance ); diff -Nru mlt-7.4.0/src/mlt++/MltAnimation.h mlt-7.6.0/src/mlt++/MltAnimation.h --- mlt-7.4.0/src/mlt++/MltAnimation.h 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/mlt++/MltAnimation.h 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /** * MltAnimation.h - MLT Wrapper - * Copyright (C) 2015-2018 Meltytech, LLC + * Copyright (C) 2015-2021 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -45,7 +45,9 @@ bool is_key( int position ); mlt_keyframe_type keyframe_type( int position ); int next_key( int position ); + bool next_key( int position, int& key ); int previous_key( int position ); + bool previous_key( int position, int& key ); int key_count(); int key_get( int index, int& frame, mlt_keyframe_type& ); int key_get_frame( int index ); diff -Nru mlt-7.4.0/src/mlt++/MltProperties.cpp mlt-7.6.0/src/mlt++/MltProperties.cpp --- mlt-7.4.0/src/mlt++/MltProperties.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/mlt++/MltProperties.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /** * MltProperties.cpp - MLT Wrapper - * Copyright (C) 2004-2021 Meltytech, LLC + * Copyright (C) 2004-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -193,6 +193,11 @@ return mlt_properties_set_data( get_properties( ), name, value, size, destructor, serialiser ); } +int Properties::copy( Properties &that, const char *prefix ) +{ + return mlt_properties_copy( get_properties( ), that.get_properties( ), prefix ); +} + void Properties::pass_property( Properties &that, const char *name ) { return mlt_properties_pass_property( get_properties( ), that.get_properties( ), name ); diff -Nru mlt-7.4.0/src/mlt++/MltProperties.h mlt-7.6.0/src/mlt++/MltProperties.h --- mlt-7.4.0/src/mlt++/MltProperties.h 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/mlt++/MltProperties.h 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /** * MltProperties.h - MLT Wrapper - * Copyright (C) 2004-2021 Meltytech, LLC + * Copyright (C) 2004-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -70,6 +70,7 @@ int set( const char *name, int64_t value ); int set( const char *name, double value ); int set( const char *name, void *value, int size, mlt_destructor destroy = NULL, mlt_serialiser serial = NULL ); + int copy( Properties &that, const char *prefix ); void pass_property( Properties &that, const char *name ); int pass_values( Properties &that, const char *prefix ); int pass_list( Properties &that, const char *list ); diff -Nru mlt-7.4.0/src/mlt++/MltPushConsumer.cpp mlt-7.6.0/src/mlt++/MltPushConsumer.cpp --- mlt-7.4.0/src/mlt++/MltPushConsumer.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/mlt++/MltPushConsumer.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -1,7 +1,6 @@ /** * MltPushConsumer.cpp - MLT Wrapper - * Copyright (C) 2004-2015 Meltytech, LLC - * Author: Charles Yates + * Copyright (C) 2004-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -104,9 +103,9 @@ int w = get_int( "render_width" ); int h = get_int( "render_height" ); frame->set( "consumer_aspect_ratio", get_double( "render_aspect_ratio" ) ); - frame->set( "consumer_deinterlace", get_int( "deinterlace" ) ); - frame->set( "deinterlace_method", get_int( "deinterlace_method" ) ); - frame->set( "rescale.interp", get( "rescale" ) ); + frame->set( "consumer.progressive", get_int( "progressive" ) | get_int( "deinterlace" ) ); + frame->set( "consumer.deinterlacer", get("deinterlacer")? get("deinterlacer") : get("deinterlace_method") ); + frame->set( "consumer.rescale", get( "rescale" ) ); // Render the frame frame->get_image( format, w, h ); diff -Nru mlt-7.4.0/src/mlt++/mlt++.vers mlt-7.6.0/src/mlt++/mlt++.vers --- mlt-7.4.0/src/mlt++/mlt++.vers 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/mlt++/mlt++.vers 2022-04-19 08:45:42.000000000 +0000 @@ -708,3 +708,12 @@ "Mlt::Service::Service(Mlt::Service*)"; }; } MLTPP_7.1.0; + +MLT_7.6.0 { + global: + extern "C++" { + "Mlt::Animation::next_key(int, int&)"; + "Mlt::Animation::previous_key(int, int&)"; + "Mlt::Properties::copy(Mlt::Properties&, char const*)"; + }; +} MLT_7.4.0; diff -Nru mlt-7.4.0/src/modules/avformat/consumer_avformat.c mlt-7.6.0/src/modules/avformat/consumer_avformat.c --- mlt-7.4.0/src/modules/avformat/consumer_avformat.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/consumer_avformat.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * consumer_avformat.c -- an encoder based on avformat - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1918,7 +1918,7 @@ struct SwsContext *context = sws_getContext( width, height, srcfmt, width, height, pix_fmt, flags, NULL, NULL, NULL); int src_colorspace = mlt_properties_get_int( frame_properties, "colorspace" ); - int src_full_range = mlt_properties_get_int( frame_properties, "full_luma" ); + int src_full_range = mlt_properties_get_int( frame_properties, "full_range" ); mlt_set_luma_transfer( context, src_colorspace, dst_colorspace, src_full_range, dst_full_range ); sws_scale( context, (const uint8_t* const*) video_avframe.data, video_avframe.linesize, 0, height, converted_avframe->data, converted_avframe->linesize); diff -Nru mlt-7.4.0/src/modules/avformat/consumer_avformat.yml mlt-7.6.0/src/modules/avformat/consumer_avformat.yml --- mlt-7.4.0/src/modules/avformat/consumer_avformat.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/consumer_avformat.yml 2022-04-19 08:45:42.000000000 +0000 @@ -134,7 +134,7 @@ unit: frames/second # These are common to all consumers. - - identifier: deinterlace_method + - identifier: deinterlacer title: Deinterlacer type: string default: yadif diff -Nru mlt-7.4.0/src/modules/avformat/factory.c mlt-7.6.0/src/modules/avformat/factory.c --- mlt-7.4.0/src/modules/avformat/factory.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/factory.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * factory.c -- the factory method interfaces - * Copyright (C) 2003-2020 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -339,6 +339,7 @@ mlt_properties_set ( metadata, "version", LIBAVFILTER_IDENT ); mlt_properties_set ( metadata, "identifier" , id ); mlt_properties_set ( metadata, "description" , f->description ); + mlt_properties_set ( metadata, "notes" , "Many parameters support animated values (keyframes) but only the numeric ones. Many numeric properties have type string because they accept an expression (see FFmpeg documentation) even though they evaluate to a numeric value." ); mlt_properties_set ( metadata, "creator" , "libavfilter maintainers" ); mlt_properties_set ( metadata, "type" , "filter" ); @@ -395,6 +396,13 @@ } #endif +static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) +{ + char file[ PATH_MAX ]; + snprintf( file, PATH_MAX, "%s/avformat/%s", mlt_environment( "MLT_DATA" ), (char*) data ); + return mlt_properties_parse_yaml( file ); +} + MLT_REPOSITORY { #ifdef CODECS @@ -403,12 +411,18 @@ MLT_REGISTER( mlt_service_producer_type, "avformat-novalidate", create_service ); MLT_REGISTER_METADATA( mlt_service_consumer_type, "avformat", avformat_metadata, NULL ); MLT_REGISTER_METADATA( mlt_service_producer_type, "avformat", avformat_metadata, NULL ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "avformat-novalidate", metadata, "producer_avformat-novalidate.yml" ); #endif #ifdef FILTERS MLT_REGISTER( mlt_service_filter_type, "avcolour_space", create_service ); MLT_REGISTER( mlt_service_filter_type, "avcolor_space", create_service ); MLT_REGISTER( mlt_service_filter_type, "avdeinterlace", create_service ); MLT_REGISTER( mlt_service_filter_type, "swscale", create_service ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "avcolour_space", metadata, "filter_avcolour_space.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "avcolor_space", metadata, "filter_avcolour_space.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "avdeinterlace", metadata, "filter_avdeinterlace.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "swscale", metadata, "filter_swscale.yml" ); + #ifdef AVFILTER char dirname[PATH_MAX]; @@ -444,5 +458,6 @@ #endif #ifdef SWRESAMPLE MLT_REGISTER( mlt_service_filter_type, "swresample", create_service ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "swresample", metadata, "filter_swresample.yml" ); #endif } diff -Nru mlt-7.4.0/src/modules/avformat/filter_avcolour_space.c mlt-7.6.0/src/modules/avformat/filter_avcolour_space.c --- mlt-7.4.0/src/modules/avformat/filter_avcolour_space.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/filter_avcolour_space.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_avcolour_space.c -- Colour space filter - * Copyright (C) 2004-2020 Meltytech, LLC + * Copyright (C) 2004-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -78,7 +78,7 @@ // returns set_lumage_transfer result static int av_convert_image( uint8_t *out, uint8_t *in, int out_fmt, int in_fmt, int out_width, int out_height, int in_width, int in_height, - int src_colorspace, int dst_colorspace, int use_full_range ) + int src_colorspace, int dst_colorspace, int src_full_range, int dst_full_range ) { uint8_t *in_data[4]; int in_stride[4]; @@ -102,7 +102,7 @@ // libswscale wants the RGB colorspace to be SWS_CS_DEFAULT, which is = SWS_CS_ITU601. if ( out_fmt == AV_PIX_FMT_RGB24 || out_fmt == AV_PIX_FMT_RGBA ) dst_colorspace = 601; - error = mlt_set_luma_transfer( context, src_colorspace, dst_colorspace, use_full_range, use_full_range ); + error = mlt_set_luma_transfer( context, src_colorspace, dst_colorspace, src_full_range, dst_full_range ); sws_scale(context, (const uint8_t* const*) in_data, in_stride, 0, in_height, out_data, out_stride); sws_freeContext( context ); @@ -129,18 +129,20 @@ MLT_PRODUCER_SERVICE( mlt_frame_get_original_producer( frame ) ) ); int profile_colorspace = profile ? profile->colorspace : 601; int colorspace = mlt_properties_get_int( properties, "colorspace" ); - int force_full_luma = 0; int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); + int src_full_range = mlt_properties_get_int(properties, "full_range"); + const char* dst_color_range = mlt_properties_get(properties, "consumer.color_range"); + int dst_full_range = dst_color_range && (!strcmp("pc", dst_color_range) || !strcmp("jpeg", dst_color_range)); if (out_width <= 0) out_width = width; if (out_height <= 0) out_height = height; - mlt_log_debug( NULL, "[filter avcolor_space] %s @ %dx%d -> %s @ %dx%d space %d->%d\n", - mlt_image_format_name( *format ), width, height, mlt_image_format_name( output_format ), - out_width, out_height, colorspace, profile_colorspace ); + mlt_log_debug(NULL, "[filter avcolor_space] %s @ %dx%d -> %s @ %dx%d space %d->%d full %d->%d\n", + mlt_image_format_name(*format), width, height, mlt_image_format_name(output_format), + out_width, out_height, colorspace, profile_colorspace, src_full_range, dst_full_range); int in_fmt = convert_mlt_to_av_cs( *format ); int out_fmt = convert_mlt_to_av_cs( output_format ); @@ -185,13 +187,14 @@ // Update the output if ( !av_convert_image( output, *image, out_fmt, in_fmt, out_width, out_height, width, height, - colorspace, profile_colorspace, force_full_luma ) ) + colorspace, profile_colorspace, src_full_range, dst_full_range) ) { // The new colorspace is only valid if destination is YUV. if ( output_format == mlt_image_yuv422 || output_format == mlt_image_yuv420p || output_format == mlt_image_yuv422p16 ) mlt_properties_set_int( properties, "colorspace", profile_colorspace ); + mlt_properties_set_int(properties, "full_range", dst_full_range); } *image = output; *format = output_format; @@ -249,10 +252,6 @@ if ( !frame->convert_image ) frame->convert_image = convert_image; -// Not working yet - see comment for get_image() above. -// mlt_frame_push_service( frame, mlt_service_profile( MLT_FILTER_SERVICE( filter ) ) ); -// mlt_frame_push_get_image( frame, get_image ); - return frame; } diff -Nru mlt-7.4.0/src/modules/avformat/filter_avcolour_space.yml mlt-7.6.0/src/modules/avformat/filter_avcolour_space.yml --- mlt-7.4.0/src/modules/avformat/filter_avcolour_space.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/filter_avcolour_space.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,16 @@ +schema_version: 7.0 +type: filter +identifier: avcolor_space +title: FFmpeg Image Converter +version: 1 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +url: http://www.ffmpeg.org/ +tags: + - Video + - Hidden +description: Converts the colorspace and pixel format. +notes: > + This is not intended to be created directly. Rather, the loader producer + loads it if it is available to set the convert_image function pointer on frames. diff -Nru mlt-7.4.0/src/modules/avformat/filter_avdeinterlace.c mlt-7.6.0/src/modules/avformat/filter_avdeinterlace.c --- mlt-7.4.0/src/modules/avformat/filter_avdeinterlace.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/filter_avdeinterlace.c 2022-04-19 08:45:42.000000000 +0000 @@ -297,7 +297,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; - int deinterlace = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace" ); + int deinterlace = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "consumer.progressive" ); // Determine if we need a writable version or not if ( deinterlace && !writable ) diff -Nru mlt-7.4.0/src/modules/avformat/filter_avdeinterlace.yml mlt-7.6.0/src/modules/avformat/filter_avdeinterlace.yml --- mlt-7.4.0/src/modules/avformat/filter_avdeinterlace.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/filter_avdeinterlace.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,17 @@ +schema_version: 7.0 +type: filter +identifier: avdeinterlace +title: Legacy FFmpeg Deinterlacer (*DEPRECATED*) +version: 1 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +url: http://www.ffmpeg.org/ +tags: + - Video + - Hidden +description: Deinterlace interlaced video. +notes: > + This is not intended to be created directly. Rather, the loader producer + loads it if it is available to set deinterlace interlaced input when the + consumer or profile is set to progressive. diff -Nru mlt-7.4.0/src/modules/avformat/filter_avfilter.c mlt-7.6.0/src/modules/avformat/filter_avfilter.c --- mlt-7.4.0/src/modules/avformat/filter_avfilter.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/filter_avfilter.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_avfilter.c -- provide various filters based on libavfilter - * Copyright (C) 2016-2021 Meltytech, LLC + * Copyright (C) 2016-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -754,13 +754,13 @@ pdata->avinframe->height = *height; pdata->avinframe->format = mlt_to_av_image_format( *format ); pdata->avinframe->sample_aspect_ratio = (AVRational) { - profile->sample_aspect_num, profile->frame_rate_den }; + profile->sample_aspect_num, profile->sample_aspect_den }; pdata->avinframe->pts = pos; pdata->avinframe->interlaced_frame = !mlt_properties_get_int( frame_properties, "progressive" ); pdata->avinframe->top_field_first = mlt_properties_get_int( frame_properties, "top_field_first" ); pdata->avinframe->color_primaries = mlt_properties_get_int( frame_properties, "color_primaries" ); pdata->avinframe->color_trc = mlt_properties_get_int( frame_properties, "color_trc" ); - pdata->avinframe->color_range = mlt_properties_get_int( frame_properties, "full_luma" )? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + pdata->avinframe->color_range = mlt_properties_get_int( frame_properties, "full_range" )? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; switch (mlt_properties_get_int( frame_properties, "colorspace" )) { diff -Nru mlt-7.4.0/src/modules/avformat/filter_swresample.c mlt-7.6.0/src/modules/avformat/filter_swresample.c --- mlt-7.4.0/src/modules/avformat/filter_swresample.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/filter_swresample.c 2022-04-19 08:45:42.000000000 +0000 @@ -158,7 +158,7 @@ // Determine the input/output channel layout. in.layout = mlt_get_channel_layout_or_default( mlt_properties_get( frame_properties, "channel_layout" ), in.channels ); - out.layout = mlt_get_channel_layout_or_default( mlt_properties_get( frame_properties, "consumer_channel_layout" ), out.channels ); + out.layout = mlt_get_channel_layout_or_default( mlt_properties_get( frame_properties, "consumer.channel_layout" ), out.channels ); if( in.format == out.format && in.frequency == out.frequency && diff -Nru mlt-7.4.0/src/modules/avformat/filter_swresample.yml mlt-7.6.0/src/modules/avformat/filter_swresample.yml --- mlt-7.4.0/src/modules/avformat/filter_swresample.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/filter_swresample.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,17 @@ +schema_version: 7.0 +type: filter +identifier: swresample +title: FFmpeg Audio Resampler +version: 1 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +url: http://www.ffmpeg.org/ +tags: + - Audio + - Hidden +description: Converts the audio sample rate. +notes: > + This is not intended to be created directly. Rather, the loader producer + loads it if it is available to set the audio resampler to normalize inputs + to the consumer audio frequency. diff -Nru mlt-7.4.0/src/modules/avformat/filter_swscale.c mlt-7.6.0/src/modules/avformat/filter_swscale.c --- mlt-7.4.0/src/modules/avformat/filter_swscale.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/filter_swscale.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_swscale.c -- image scaling filter - * Copyright (C) 2008-2018 Meltytech, LLC + * Copyright (C) 2008-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,18 +20,20 @@ #include #include #include - +#include +#include // ffmpeg Header files #include #include #include +#include #include #include #include -#define IMAGE_ALIGN (1) +#define MAX_THREADS (6) static inline int convert_mlt_to_av_cs( mlt_image_format format ) { @@ -52,7 +54,7 @@ value = AV_PIX_FMT_YUV420P; break; default: - fprintf( stderr, "Invalid format...\n" ); + mlt_log_error(NULL, "[filter swscale] Invalid format %s\n", mlt_image_format_name(format)); break; } @@ -61,11 +63,13 @@ static int filter_scale( mlt_frame frame, uint8_t **image, mlt_image_format *format, int iwidth, int iheight, int owidth, int oheight ) { + int result = 0; + // Get the properties mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the requested interpolation method - char *interps = mlt_properties_get( properties, "rescale.interp" ); + char *interps = mlt_properties_get( properties, "consumer.rescale" ); // Convert to the SwScale flag int interp = SWS_BILINEAR; @@ -91,77 +95,206 @@ // Set swscale flags to get good quality interp |= SWS_FULL_CHR_H_INP | SWS_FULL_CHR_H_INT | SWS_ACCURATE_RND; - // Determine the output image size. - int out_size = mlt_image_format_size( *format, owidth, oheight, NULL ); - - switch ( *format ) - { - case mlt_image_yuv422: - case mlt_image_rgb: - case mlt_image_rgba: - break; - default: - // XXX: we only know how to rescale packed formats - return 1; - } - // Convert the pixel formats int avformat = convert_mlt_to_av_cs( *format ); - // Fill out the AVPictures - uint8_t *in_data[4]; - int in_stride[4]; - uint8_t *out_data[4]; - int out_stride[4]; + // Determine the output image size. + int out_size = mlt_image_format_size( *format, owidth, oheight, NULL ); uint8_t *outbuf = mlt_pool_alloc( out_size ); - av_image_fill_arrays(in_data, in_stride, *image, avformat, iwidth, iheight, IMAGE_ALIGN); - av_image_fill_arrays(out_data, out_stride, outbuf, avformat, owidth, oheight, IMAGE_ALIGN); + // Create the context + struct SwsContext *context = sws_alloc_context(); + if (outbuf && context) { + AVFrame *avinframe = av_frame_alloc(); + AVFrame *avoutframe = av_frame_alloc(); + + av_opt_set_int(context, "srcw", iwidth, 0); + av_opt_set_int(context, "srch", iheight, 0); + av_opt_set_int(context, "src_format", avformat, 0); + av_opt_set_int(context, "dstw", owidth, 0); + av_opt_set_int(context, "dsth", oheight, 0); + av_opt_set_int(context, "dst_format", avformat, 0); + av_opt_set_int(context, "sws_flags", interp, 0); +#if LIBSWSCALE_VERSION_MAJOR >= 6 + av_opt_set_int(context, "threads", MIN(mlt_slices_count_normal(), MAX_THREADS), 0); +#endif + result = sws_init_context(context, NULL, NULL); + if (result < 0) { + mlt_log_error(NULL, "[filter swscale] Initializing swscale failed with %d (%s)\n", result, av_err2str(result)); + result = 1; + goto exit; + } + + // Setup the input image + avinframe->width = iwidth; + avinframe->height = iheight; + avinframe->format = avformat; + avinframe->sample_aspect_ratio = av_d2q(mlt_frame_get_aspect_ratio(frame), 1024); + avinframe->interlaced_frame = !mlt_properties_get_int(properties, "progressive"); + avinframe->top_field_first = mlt_properties_get_int(properties, "top_field_first"); + mlt_image_format_planes(*format, iwidth, iheight, *image, avinframe->data, avinframe->linesize); + + // Setup the output image + av_frame_copy_props(avoutframe, avinframe); + avoutframe->width = owidth; + avoutframe->height = oheight; + avoutframe->format = avformat; + + result = av_frame_get_buffer(avoutframe, 0); + if (result < 0) { + mlt_log_error(NULL, "[filter swscale] Cannot allocate output frame buffer\n"); + result = 1; + goto exit; + } - // Create the context and output image - struct SwsContext *context = sws_getContext( iwidth, iheight, avformat, owidth, oheight, avformat, interp, NULL, NULL, NULL); - if ( context ) - { // Perform the scaling - sws_scale( context, (const uint8_t **) in_data, in_stride, 0, iheight, out_data, out_stride); - sws_freeContext( context ); +#if LIBSWSCALE_VERSION_MAJOR >= 6 + result = sws_scale_frame(context, avoutframe, avinframe); +#else + result = sws_scale(context, (const uint8_t **) avinframe->data, avinframe->linesize, 0, iheight, avoutframe->data, avoutframe->linesize); +#endif + if (result < 0) { + mlt_log_error(NULL, "[filter swscale] sws_scale_frame failed with %d (%s)\n", result, av_err2str(result)); + result = 1; + goto exit; + } + sws_freeContext(context); + context = NULL; - // Now update the frame - mlt_frame_set_image( frame, outbuf, out_size, mlt_pool_release ); + // Sanity check the output frame + if (owidth != avoutframe->width || oheight != avoutframe->height) { + mlt_log_error(NULL, "[filter swscale] Unexpected output size\n"); + result = 1; + goto exit; + } + + // Copy the filter output into the output buffer + if (*format == mlt_image_yuv420p) { + int i = 0; + int p = 0; + int widths[3] = { owidth, owidth / 2, owidth / 2 }; + int heights[3] = { oheight, oheight / 2, oheight / 2 }; + uint8_t* dst = outbuf; + for (p = 0; p < 3; p++) { + uint8_t* src = avoutframe->data[p]; + for (i = 0; i < heights[p]; i++) { + memcpy(dst, src, widths[p]); + dst += widths[p]; + src += avoutframe->linesize[p]; + } + } + } else { + int i; + uint8_t* dst = outbuf; + uint8_t* src = avoutframe->data[0]; + int stride = mlt_image_format_size(*format, owidth, 1, NULL); + for (i = 0; i < oheight; i++) { + memcpy(dst, src, stride); + dst += stride; + src += avoutframe->linesize[0]; + } + } + + // Now update the MLT frame + mlt_frame_set_image(frame, outbuf, out_size, mlt_pool_release); - // Return the output + // Return the output image *image = outbuf; // Scale the alpha channel only if exists and not correct size int alpha_size = 0; - mlt_properties_get_data( properties, "alpha", &alpha_size ); - if ( alpha_size > 0 && alpha_size != ( owidth * oheight ) ) - { + mlt_properties_get_data(properties, "alpha", &alpha_size); + if (alpha_size > 0 && alpha_size != (owidth * oheight)) { // Create the context and output image uint8_t *alpha = mlt_frame_get_alpha( frame ); - if ( alpha ) - { - avformat = AV_PIX_FMT_GRAY8; - struct SwsContext *context = sws_getContext( iwidth, iheight, avformat, owidth, oheight, avformat, interp, NULL, NULL, NULL); - outbuf = mlt_pool_alloc( owidth * oheight ); - av_image_fill_arrays(in_data, in_stride, alpha, avformat, iwidth, iheight, IMAGE_ALIGN); - av_image_fill_arrays(out_data, out_stride, outbuf, avformat, owidth, oheight, IMAGE_ALIGN); - - // Perform the scaling - sws_scale( context, (const uint8_t **) in_data, in_stride, 0, iheight, out_data, out_stride); - sws_freeContext( context ); - - // Set it back on the frame - mlt_frame_set_alpha( frame, outbuf, owidth * oheight, mlt_pool_release ); + + if (alpha) { + outbuf = mlt_pool_alloc(owidth * oheight); + context = sws_alloc_context(); + + if (outbuf && context) { + av_frame_unref(avinframe); + av_frame_unref(avoutframe); + + avformat = AV_PIX_FMT_GRAY8; + av_opt_set_int(context, "srcw", iwidth, 0); + av_opt_set_int(context, "srch", iheight, 0); + av_opt_set_int(context, "src_format", avformat, 0); + av_opt_set_int(context, "dstw", owidth, 0); + av_opt_set_int(context, "dsth", oheight, 0); + av_opt_set_int(context, "dst_format", avformat, 0); + av_opt_set_int(context, "sws_flags", interp, 0); + #if LIBSWSCALE_VERSION_MAJOR >= 6 + av_opt_set_int(context, "threads", MIN(mlt_slices_count_normal(), MAX_THREADS), 0); + #endif + result = sws_init_context(context, NULL, NULL); + if (result < 0) { + mlt_log_error(NULL, "[filter swscale] Initializing swscale alpha failed with %d (%s)\n", result, av_err2str(result)); + result = 1; + goto exit; + } + + // Setup the input image + avinframe->width = iwidth; + avinframe->height = iheight; + avinframe->format = avformat; + avinframe->data[0] = alpha; + avinframe->linesize[0] = iwidth; + + // Setup the output image + avoutframe->width = owidth; + avoutframe->height = oheight; + avoutframe->format = avformat; + + result = av_frame_get_buffer(avoutframe, 0); + if (result < 0) { + mlt_log_error(NULL, "[filter swscale] Cannot allocate alpha frame buffer\n"); + result = 1; + goto exit; + } + + // Perform the scaling +#if LIBSWSCALE_VERSION_MAJOR >= 6 + result = sws_scale_frame(context, avoutframe, avinframe); +#else + result = sws_scale(context, (const uint8_t **) avinframe->data, avinframe->linesize, 0, iheight, avoutframe->data, avoutframe->linesize); +#endif + if (result < 0) { + mlt_log_error(NULL, "[filter swscale] sws_scale_frame alpha failed with %d (%s) %d %d\n", result, av_err2str(result), avoutframe->width, avoutframe->height); + result = 1; + goto exit; + } + sws_freeContext(context); + context = NULL; + + // Sanity check the output frame + if (owidth != avoutframe->width || oheight != avoutframe->height) { + mlt_log_error(NULL, "[filter swscale] Unexpected output alpha size\n"); + result = 1; + goto exit; + } + + int i; + uint8_t* dst = outbuf; + uint8_t* src = avoutframe->data[0]; + for (i = 0; i < oheight; i++) { + memcpy(dst, src, owidth); + dst += owidth; + src += avoutframe->linesize[0]; + } + + // Set it back on the frame + mlt_frame_set_alpha(frame, outbuf, owidth * oheight, mlt_pool_release ); + } } } - - return 0; - } - else - { - return 1; + +exit: + av_frame_free(&avinframe); + av_frame_free(&avoutframe); + sws_freeContext(context); } + return result; } /** Constructor for the filter. diff -Nru mlt-7.4.0/src/modules/avformat/filter_swscale.yml mlt-7.6.0/src/modules/avformat/filter_swscale.yml --- mlt-7.4.0/src/modules/avformat/filter_swscale.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/filter_swscale.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,17 @@ +schema_version: 7.0 +type: filter +identifier: swscale +title: FFmpeg Image Scaler +version: 1 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +url: http://www.ffmpeg.org/ +tags: + - Video + - Hidden +description: Change the resolution of an image. +notes: > + This is not intended to be created directly. Rather, the rescale filter + loads it if it is available to normalize video and image inputs to the + consumer/profile resolution. diff -Nru mlt-7.4.0/src/modules/avformat/producer_avformat.c mlt-7.6.0/src/modules/avformat/producer_avformat.c --- mlt-7.4.0/src/modules/avformat/producer_avformat.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/producer_avformat.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * producer_avformat.c -- avformat producer - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -113,7 +113,7 @@ unsigned int invalid_dts_counter; mlt_cache image_cache; int yuv_colorspace, color_primaries, color_trc; - int full_luma; + int full_range; pthread_mutex_t video_mutex; pthread_mutex_t audio_mutex; mlt_deque apackets; @@ -444,7 +444,7 @@ mlt_properties_set_int( meta_media, key, codec_params->width * codec_params->height > 750000 ? 709 : 601 ); break; default: -// mlt_properties_set_int( meta_media, key, codec_context->colorspace ); + mlt_properties_set_int( meta_media, key, codec_params->color_space ); break; } if ( codec_params->color_trc && codec_params->color_trc != AVCOL_TRC_UNSPECIFIED ) @@ -780,6 +780,41 @@ } return result; } + +static int setup_autorotate_filters(producer_avformat self) +{ + int error = 0; + + if (!self->vfilter_graph && self->autorotate && self->video_index != -1) { + mlt_properties properties = MLT_PRODUCER_PROPERTIES(self->parent); + double theta = get_rotation(properties, self->video_format->streams[self->video_index]); + + if (fabs(theta - 90) < 1.0) { + error = ( setup_video_filters(self) < 0 ); + AVFilterContext *last_filter = self->vfilter_out; + if (!error) error = ( insert_filter(self->vfilter_graph, &last_filter, "transpose", "clock") < 0 ); + if (!error) error = ( avfilter_link(self->vfilter_in, 0, last_filter, 0) < 0 ); + if (!error) error = ( avfilter_graph_config(self->vfilter_graph, NULL) < 0 ); + } else if (fabs(theta - 180) < 1.0) { + error = ( setup_video_filters(self) < 0 ); + AVFilterContext *last_filter = self->vfilter_out; + if (!error) error = ( insert_filter(self->vfilter_graph, &last_filter, "hflip", NULL) < 0 ); + if (!error) error = ( insert_filter(self->vfilter_graph, &last_filter, "vflip", NULL) < 0 ); + if (!error) error = ( avfilter_link(self->vfilter_in, 0, last_filter, 0) < 0 ); + if (!error) error = ( avfilter_graph_config(self->vfilter_graph, NULL) < 0 ); + } else if (fabs(theta - 270) < 1.0) { + error = ( setup_video_filters(self) < 0 ); + AVFilterContext *last_filter = self->vfilter_out; + if (!error) error = ( insert_filter(self->vfilter_graph, &last_filter, "transpose", "cclock") < 0 ); + if (!error) error = ( avfilter_link(self->vfilter_in, 0, last_filter, 0) < 0 ); + if (!error) error = ( avfilter_graph_config(self->vfilter_graph, NULL) < 0 ); + } + } + if (error && self->vfilter_graph) { + avfilter_graph_free(&self->vfilter_graph); + } + return error; +} #endif /** Open the file. @@ -933,33 +968,9 @@ get_audio_streams_info( self ); #ifdef AVFILTER - // Setup autorotate filters. - if (self->video_index != -1) { + if (!test_open) { self->autorotate = !mlt_properties_get(properties, "autorotate") || mlt_properties_get_int(properties, "autorotate"); - if (!test_open && self->autorotate && !self->vfilter_graph) { - double theta = get_rotation(properties, self->video_format->streams[self->video_index]); - - if (fabs(theta - 90) < 1.0) { - error = ( setup_video_filters(self) < 0 ); - AVFilterContext *last_filter = self->vfilter_out; - if (!error) error = ( insert_filter(self->vfilter_graph, &last_filter, "transpose", "clock") < 0 ); - if (!error) error = ( avfilter_link(self->vfilter_in, 0, last_filter, 0) < 0 ); - if (!error) error = ( avfilter_graph_config(self->vfilter_graph, NULL) < 0 ); - } else if (fabs(theta - 180) < 1.0) { - error = ( setup_video_filters(self) < 0 ); - AVFilterContext *last_filter = self->vfilter_out; - if (!error) error = ( insert_filter(self->vfilter_graph, &last_filter, "hflip", NULL) < 0 ); - if (!error) error = ( insert_filter(self->vfilter_graph, &last_filter, "vflip", NULL) < 0 ); - if (!error) error = ( avfilter_link(self->vfilter_in, 0, last_filter, 0) < 0 ); - if (!error) error = ( avfilter_graph_config(self->vfilter_graph, NULL) < 0 ); - } else if (fabs(theta - 270) < 1.0) { - error = ( setup_video_filters(self) < 0 ); - AVFilterContext *last_filter = self->vfilter_out; - if (!error) error = ( insert_filter(self->vfilter_graph, &last_filter, "transpose", "cclock") < 0 ); - if (!error) error = ( avfilter_link(self->vfilter_in, 0, last_filter, 0) < 0 ); - if (!error) error = ( avfilter_graph_config(self->vfilter_graph, NULL) < 0 ); - } - } + error = setup_autorotate_filters(self); } #endif } @@ -1420,7 +1431,7 @@ // returns resulting YUV colorspace static int convert_image( producer_avformat self, AVFrame *frame, uint8_t *buffer, int pix_fmt, - mlt_image_format *format, int width, int height, uint8_t **alpha ) + mlt_image_format *format, int width, int height, uint8_t **alpha, int dst_full_range ) { mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( self->parent ) ); int result = self->yuv_colorspace; @@ -1465,7 +1476,7 @@ out_stride[0] = width; out_stride[1] = width >> 1; out_stride[2] = width >> 1; - if ( !mlt_set_luma_transfer( context, self->yuv_colorspace, profile->colorspace, self->full_luma, self->full_luma ) ) + if ( !mlt_set_luma_transfer( context, self->yuv_colorspace, profile->colorspace, self->full_range, dst_full_range ) ) result = profile->colorspace; sws_scale( context, (const uint8_t* const*) frame->data, frame->linesize, 0, height, out_data, out_stride); @@ -1480,7 +1491,7 @@ int out_stride[4]; av_image_fill_arrays(out_data, out_stride, buffer, AV_PIX_FMT_RGB24, width, height, IMAGE_ALIGN); // libswscale wants the RGB colorspace to be SWS_CS_DEFAULT, which is = SWS_CS_ITU601. - mlt_set_luma_transfer( context, self->yuv_colorspace, 601, self->full_luma, 0 ); + mlt_set_luma_transfer( context, self->yuv_colorspace, 601, self->full_range, 1 ); sws_scale( context, (const uint8_t* const*) frame->data, frame->linesize, 0, height, out_data, out_stride); sws_freeContext( context ); @@ -1494,7 +1505,7 @@ int out_stride[4]; av_image_fill_arrays(out_data, out_stride, buffer, AV_PIX_FMT_RGBA, width, height, IMAGE_ALIGN); // libswscale wants the RGB colorspace to be SWS_CS_DEFAULT, which is = SWS_CS_ITU601. - mlt_set_luma_transfer( context, self->yuv_colorspace, 601, self->full_luma, 0 ); + mlt_set_luma_transfer( context, self->yuv_colorspace, 601, self->full_range, 1 ); sws_scale( context, (const uint8_t* const*) frame->data, frame->linesize, 0, height, out_data, out_stride); sws_freeContext( context ); @@ -1510,10 +1521,10 @@ .dst_format = AV_PIX_FMT_YUYV422, .src_colorspace = self->yuv_colorspace, .dst_colorspace = profile->colorspace, - .src_full_range = self->full_luma, - .dst_full_range = 0, + .src_full_range = self->full_range, + .dst_full_range = dst_full_range, }; - ctx.src_format = (self->full_luma && src_pix_fmt == AV_PIX_FMT_YUV422P) ? AV_PIX_FMT_YUVJ422P : src_pix_fmt; + ctx.src_format = (self->full_range && src_pix_fmt == AV_PIX_FMT_YUV422P) ? AV_PIX_FMT_YUVJ422P : src_pix_fmt; ctx.src_desc = av_pix_fmt_desc_get( ctx.src_format ); ctx.dst_desc = av_pix_fmt_desc_get( ctx.dst_format ); ctx.flags = mlt_get_sws_flags(width, height, ctx.src_format, width, height, ctx.dst_format); @@ -1618,6 +1629,8 @@ uint8_t *alpha = NULL; int got_picture = 0; int image_size = 0; + const char* dst_color_range = mlt_properties_get(frame_properties, "consumer.color_range"); + int dst_full_range = dst_color_range && (!strcmp("pc", dst_color_range) || !strcmp("jpeg", dst_color_range)); pthread_mutex_lock( &self->video_mutex ); mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); @@ -1680,6 +1693,7 @@ *format = mlt_properties_get_int( orig_props, "format" ); set_image_size( self, width, height ); mlt_properties_pass_property(frame_properties, orig_props, "colorspace"); + mlt_properties_set_int(frame_properties, "full_range", dst_full_range); got_picture = 1; goto exit_get_image; } @@ -1708,23 +1722,23 @@ context = self->video_format; stream = context->streams[ self->video_index ]; codec_params = stream->codecpar; - if ( *format == mlt_image_none || *format == mlt_image_movit || - codec_params->format == AV_PIX_FMT_ARGB || - codec_params->format == AV_PIX_FMT_RGBA || - codec_params->format == AV_PIX_FMT_ABGR || - codec_params->format == AV_PIX_FMT_BGRA ) - *format = pick_image_format( codec_params->format ); - else if ( codec_params->format == AV_PIX_FMT_BAYER_RGGB16LE ) { - if ( *format == mlt_image_yuv422 ) - *format = mlt_image_yuv420p; - else if ( *format == mlt_image_rgba ) - *format = mlt_image_rgb; - } - else if ( codec_params->format == AV_PIX_FMT_YUVA444P10LE - || codec_params->format == AV_PIX_FMT_GBRAP10LE - || codec_params->format == AV_PIX_FMT_GBRAP12LE - ) + + // Only change the requested image format for special cases + if (*format == mlt_image_none || *format == mlt_image_movit + || codec_params->format == AV_PIX_FMT_ARGB + || codec_params->format == AV_PIX_FMT_RGBA + || codec_params->format == AV_PIX_FMT_ABGR + || codec_params->format == AV_PIX_FMT_BGRA) { + *format = pick_image_format(codec_params->format); + } else if (codec_params->format == AV_PIX_FMT_BAYER_RGGB16LE + || (codec_params->format == AV_PIX_FMT_YUV420P10LE && self->full_range)) { + *format = mlt_image_rgb; + } + else if (codec_params->format == AV_PIX_FMT_YUVA444P10LE + || codec_params->format == AV_PIX_FMT_GBRAP10LE + || codec_params->format == AV_PIX_FMT_GBRAP12LE) { *format = mlt_image_rgba; + } // Duplicate the last image if necessary if ( self->video_frame && self->video_frame->linesize[0] @@ -1738,12 +1752,13 @@ int yuv_colorspace; #if USE_HWACCEL yuv_colorspace = convert_image( self, self->video_frame, *buffer, self->video_frame->format, - format, *width, *height, &alpha ); + format, *width, *height, &alpha, dst_full_range ); #else yuv_colorspace = convert_image( self, self->video_frame, *buffer, codec_params->format, - format, *width, *height, &alpha ); + format, *width, *height, &alpha, dst_full_range ); #endif mlt_properties_set_int( frame_properties, "colorspace", yuv_colorspace ); + mlt_properties_set_int( frame_properties, "full_range", dst_full_range ); got_picture = 1; } } @@ -1933,7 +1948,7 @@ if ( got_picture ) { #ifdef AVFILTER - if (self->autorotate && self->vfilter_graph) { + if (self->autorotate && !setup_autorotate_filters(self) && self->vfilter_graph) { int ret = av_buffersrc_add_frame(self->vfilter_in, self->video_frame); if (ret < 0) { got_picture = 0; @@ -1955,12 +1970,13 @@ #if USE_HWACCEL // not sure why this is really needed, but doesn't seem to work otherwise yuv_colorspace = convert_image( self, self->video_frame, *buffer, self->video_frame->format, - format, *width, *height, &alpha ); + format, *width, *height, &alpha, dst_full_range ); #else yuv_colorspace = convert_image( self, self->video_frame, *buffer, codec_params->format, - format, *width, *height, &alpha ); + format, *width, *height, &alpha, dst_full_range ); #endif mlt_properties_set_int( frame_properties, "colorspace", yuv_colorspace ); + mlt_properties_set_int( frame_properties, "full_range", dst_full_range ); self->top_field_first |= self->video_frame->top_field_first; self->top_field_first |= codec_params->field_order == AV_FIELD_TT; self->top_field_first |= codec_params->field_order == AV_FIELD_TB; @@ -2240,6 +2256,30 @@ frame_rate.den = profile->frame_rate_den; } + // Normalize broadcast frame rates for Matroska + if (self->video_format->iformat->name && strstr(self->video_format->iformat->name, "matroska")) { + switch (lrint(100000.0 * frame_rate.num / frame_rate.den)) { + case 2997003: + frame_rate.num = 30000; + frame_rate.den = 1001; + break; + case 5994006: + frame_rate.num = 60000; + frame_rate.den = 1001; + break; + case 2397602: + frame_rate.num = 24000; + frame_rate.den = 1001; + break; + case 4795204: + frame_rate.num = 48000; + frame_rate.den = 1001; + break; + default: + break; + } + } + self->video_time_base = stream->time_base; if ( mlt_properties_get( properties, "force_fps" ) ) { @@ -2304,12 +2344,12 @@ mlt_properties_set_int( properties, "meta.media.has_b_frames", self->video_codec->has_b_frames ); - self->full_luma = 0; - mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "color_range %d\n", codec_context->color_range ); - if ( codec_context->color_range == AVCOL_RANGE_JPEG ) - self->full_luma = 1; - if ( mlt_properties_get( properties, "set.force_full_luma" ) ) - self->full_luma = mlt_properties_get_int( properties, "set.force_full_luma" ); + self->full_range = codec_context->color_range == AVCOL_RANGE_JPEG; + if (mlt_properties_get(properties, "force_full_range")) { + self->full_range = mlt_properties_get_int(properties, "force_full_range"); + } else if (mlt_properties_get( properties, "set.force_full_luma")) { // deprecated + self->full_range = mlt_properties_get_int(properties, "set.force_full_luma"); + } } return self->video_index > -1; } @@ -2415,8 +2455,12 @@ mlt_properties_set_int( frame_properties, "colorspace", self->yuv_colorspace ); mlt_properties_set_int( frame_properties, "color_trc", self->color_trc ); mlt_properties_set_int( frame_properties, "color_primaries", self->color_primaries ); - mlt_properties_set_int( frame_properties, "full_luma", self->full_luma ); - mlt_properties_set( properties, "meta.media.color_range", self->full_luma? "full" : "mpeg" ); + // full_range is the current state of frame + mlt_properties_set_int( frame_properties, "full_range", self->full_range ); + // "full_luma" is deprecated but keep this for backwards compatibility for kdenlive + mlt_properties_set_int( frame_properties, "full_luma", self->full_range ); + // meta.media.color_range is the range of this producer per video_index regardless of override + mlt_properties_set( properties, "meta.media.color_range", self->full_range? "full" : "mpeg" ); // Add our image operation mlt_frame_push_service( frame, self ); @@ -2595,7 +2639,7 @@ if ( self->seekable || int_position > 0 ) { - if ( req_position > int_position ) { + if ( req_pts > pts ) { // We are behind, so skip some *ignore = lrint( timebase * (req_pts - pts) * codec_context->sample_rate ); } else if ( self->audio_index != INT_MAX && int_position > req_position + 2 && !self->is_audio_synchronizing ) { diff -Nru mlt-7.4.0/src/modules/avformat/producer_avformat-novalidate.yml mlt-7.6.0/src/modules/avformat/producer_avformat-novalidate.yml --- mlt-7.4.0/src/modules/avformat/producer_avformat-novalidate.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/producer_avformat-novalidate.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,20 @@ +schema_version: 7.0 +type: producer +identifier: avformat-novalidate +title: Non-validating FFmpeg Reader +version: 2 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +url: http://www.ffmpeg.org/ +tags: + - Audio + - Video +description: Read an audio and/or video file using FFmpeg. +notes: > + This is basically the same as the avformat producer, but it does not validate + that FFmpeg can open and read the resource. This is primarily useful in a + composition (e.g. XML) that was constructed after it was validated. Since + validation also determines the length property, you should set that yourself + on this producer after having learned it from the normal avformat producer. + See the documentation for the normal avformat producer for more information. diff -Nru mlt-7.4.0/src/modules/avformat/producer_avformat.yml mlt-7.6.0/src/modules/avformat/producer_avformat.yml --- mlt-7.4.0/src/modules/avformat/producer_avformat.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/producer_avformat.yml 2022-04-19 08:45:42.000000000 +0000 @@ -2,14 +2,11 @@ type: producer identifier: avformat title: FFmpeg Reader -version: 2 -copyright: Copyright (C) 2003-2019 Meltytech, LLC -license: LGPL +version: 3 +copyright: Meltytech, LLC +license: LGPLv2.1 language: en url: http://www.ffmpeg.org/ -creator: Charles Yates -contributor: - - Dan Dennedy tags: - Audio - Video @@ -167,6 +164,11 @@ type: float widget: checkbox + - identifier: force_full_range + title: Force Full Range Color + description: When provided, this overrides the detected color range of the video (Y'CbCr only). + type: boolean + - identifier: force_colorspace title: Force colorspace description: When provided, this overrides the detected colorspace of the video (Y'CbCr only). diff -Nru mlt-7.4.0/src/modules/avformat/resolution_scale.yml mlt-7.6.0/src/modules/avformat/resolution_scale.yml --- mlt-7.4.0/src/modules/avformat/resolution_scale.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/resolution_scale.yml 2022-04-19 08:45:42.000000000 +0000 @@ -12,6 +12,10 @@ x: 1.0 y: 1.0 +gblur: + sigma: 1.0 + sigmaV: 1.0 + pad: x: 1.0 y: 1.0 diff -Nru mlt-7.4.0/src/modules/avformat/yuv_only.txt mlt-7.6.0/src/modules/avformat/yuv_only.txt --- mlt-7.4.0/src/modules/avformat/yuv_only.txt 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/avformat/yuv_only.txt 2022-04-19 08:45:42.000000000 +0000 @@ -1,2 +1,3 @@ +fspp smartblur vaguedenoiser diff -Nru mlt-7.4.0/src/modules/core/CMakeLists.txt mlt-7.6.0/src/modules/core/CMakeLists.txt --- mlt-7.4.0/src/modules/core/CMakeLists.txt 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/CMakeLists.txt 2022-04-19 08:45:42.000000000 +0000 @@ -6,6 +6,7 @@ filter_audioconvert.c filter_audiomap.c filter_audiowave.c + filter_box_blur.c filter_brightness.c filter_channelcopy.c filter_choppy.c @@ -21,10 +22,12 @@ filter_mono.c filter_obscure.c filter_panner.c + filter_pillar_echo.c filter_rescale.c filter_resize.c filter_transition.c filter_watermark.c + image_proc.c link_timeremap.c producer_colour.c producer_consumer.c @@ -66,6 +69,7 @@ consumer_multi.yml filter_audiomap.yml filter_audiowave.yml + filter_box_blur.yml filter_brightness.yml filter_channelcopy.yml filter_choppy.yml @@ -80,6 +84,7 @@ filter_mono.yml filter_obscure.yml filter_panner.yml + filter_pillar_echo.yml filter_rescale.yml filter_resize.yml filter_transition.yml diff -Nru mlt-7.4.0/src/modules/core/consumer_multi.yml mlt-7.6.0/src/modules/core/consumer_multi.yml --- mlt-7.4.0/src/modules/core/consumer_multi.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/consumer_multi.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: consumer identifier: multi title: Multiple outputs @@ -29,7 +29,8 @@ consumer, which is how melt and the XML producer support multiple consumers. parameters: - - identifier: argument + - identifier: resource + argument: yes title: File type: string description: > diff -Nru mlt-7.4.0/src/modules/core/consumer_null.yml mlt-7.6.0/src/modules/core/consumer_null.yml --- mlt-7.4.0/src/modules/core/consumer_null.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/core/consumer_null.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,16 @@ +schema_version: 7.0 +type: consumer +identifier: "null" +title: NULL +version: 1 +copyright: Meltytech, LLC +license: LGPL +language: en +tags: + - Audio + - Video +description: A consumer that does nothing but pull frames. +notes: > + This is intentionally minimal and does not even request image or audio from + frames or fire events. It is handy for benchmarking, howevever, if you set + the consumer properties terminate_on_pause=1 and real_time=-1. diff -Nru mlt-7.4.0/src/modules/core/factory.c mlt-7.6.0/src/modules/core/factory.c --- mlt-7.4.0/src/modules/core/factory.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/factory.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * factory.c -- the factory method interfaces - * Copyright (C) 2003-2020 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,6 +27,7 @@ extern mlt_filter filter_audioconvert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_audiomap_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_audiowave_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +extern mlt_filter filter_box_blur_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_brightness_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_channelcopy_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_choppy_init(mlt_profile profile, mlt_service_type type, const char *id, char *arg); @@ -42,6 +43,7 @@ extern mlt_filter filter_mono_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_obscure_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_panner_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +extern mlt_filter filter_pillar_echo_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_rescale_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_resize_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_transition_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); @@ -76,6 +78,7 @@ MLT_REGISTER( mlt_service_filter_type, "audioconvert", filter_audioconvert_init ); MLT_REGISTER( mlt_service_filter_type, "audiomap", filter_audiomap_init ); MLT_REGISTER( mlt_service_filter_type, "audiowave", filter_audiowave_init ); + MLT_REGISTER( mlt_service_filter_type, "box_blur", filter_box_blur_init ); MLT_REGISTER( mlt_service_filter_type, "brightness", filter_brightness_init ); MLT_REGISTER( mlt_service_filter_type, "channelcopy", filter_channelcopy_init ); MLT_REGISTER( mlt_service_filter_type, "channelswap", filter_channelcopy_init ); @@ -93,6 +96,7 @@ MLT_REGISTER( mlt_service_filter_type, "mono", filter_mono_init ); MLT_REGISTER( mlt_service_filter_type, "obscure", filter_obscure_init ); MLT_REGISTER( mlt_service_filter_type, "panner", filter_panner_init ); + MLT_REGISTER( mlt_service_filter_type, "pillar_echo", filter_pillar_echo_init ); MLT_REGISTER( mlt_service_filter_type, "rescale", filter_rescale_init ); MLT_REGISTER( mlt_service_filter_type, "resize", filter_resize_init ); MLT_REGISTER( mlt_service_filter_type, "transition", filter_transition_init ); @@ -115,8 +119,12 @@ MLT_REGISTER( mlt_service_transition_type, "matte", transition_matte_init ); MLT_REGISTER_METADATA( mlt_service_consumer_type, "multi", metadata, "consumer_multi.yml" ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "null", metadata, "consumer_null.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "audiochannels", metadata, "filter_audiochannels.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "audioconvert", metadata, "filter_audioconvert.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "audiomap", metadata, "filter_audiomap.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "audiowave", metadata, "filter_audiowave.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "box_blur", metadata, "filter_box_blur.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "brightness", metadata, "filter_brightness.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "channelcopy", metadata, "filter_channelcopy.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "channelswap", metadata, "filter_channelcopy.yml" ); @@ -126,6 +134,7 @@ MLT_REGISTER_METADATA( mlt_service_filter_type, "gamma", metadata, "filter_gamma.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "greyscale", metadata, "filter_greyscale.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "grayscale", metadata, "filter_greyscale.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "imageconvert", metadata, "filter_imageconvert.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "luma", metadata, "filter_luma.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "mask_apply", metadata, "filter_mask_apply.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "mask_start", metadata, "filter_mask_start.yml" ); @@ -133,11 +142,13 @@ MLT_REGISTER_METADATA( mlt_service_filter_type, "mono", metadata, "filter_mono.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "obscure", metadata, "filter_obscure.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "panner", metadata, "filter_panner.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "pillar_echo", metadata, "filter_pillar_echo.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "rescale", metadata, "filter_rescale.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "resize", metadata, "filter_resize.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "transition", metadata, "filter_transition.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "watermark", metadata, "filter_watermark.yml" ); MLT_REGISTER_METADATA( mlt_service_link_type, "timeremap", metadata, "link_timeremap.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "abnormal", metadata, "producer_abnormal.yml" ); MLT_REGISTER_METADATA( mlt_service_producer_type, "colour", metadata, "producer_colour.yml" ); MLT_REGISTER_METADATA( mlt_service_producer_type, "color", metadata, "producer_colour.yml" ); MLT_REGISTER_METADATA( mlt_service_producer_type, "consumer", metadata, "producer_consumer.yml" ); diff -Nru mlt-7.4.0/src/modules/core/filter_audiochannels.yml mlt-7.6.0/src/modules/core/filter_audiochannels.yml --- mlt-7.4.0/src/modules/core/filter_audiochannels.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_audiochannels.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,15 @@ +schema_version: 7.0 +type: filter +identifier: audiochannels +title: Convert Audio Channel Count +version: 1 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +tags: + - Audio +description: Converts the number of audio channels. +notes: > + This is not intended to be created directly. Rather, the loader producer + loads it if it is available to automatically all inputs to have the number + of audio channels requested by the consumer. diff -Nru mlt-7.4.0/src/modules/core/filter_audioconvert.yml mlt-7.6.0/src/modules/core/filter_audioconvert.yml --- mlt-7.4.0/src/modules/core/filter_audioconvert.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_audioconvert.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,14 @@ +schema_version: 7.0 +type: filter +identifier: audioconvert +title: Audio Sample Format Converter +version: 1 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +tags: + - Audio +description: Converts the audio sample format. +notes: > + This is not intended to be created directly. Rather, the loader producer + loads it to set the convert_audio function pointer on frames. diff -Nru mlt-7.4.0/src/modules/core/filter_audiowave.yml mlt-7.6.0/src/modules/core/filter_audiowave.yml --- mlt-7.4.0/src/modules/core/filter_audiowave.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_audiowave.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,7 +1,7 @@ schema_version: 0.1 type: filter identifier: audiowave -title: Audio Waveform (*deprecated*) +title: Audio Waveform (*DEPRECATED*) version: 1 copyright: Meltytech, LLC creator: Dan Dennedy diff -Nru mlt-7.4.0/src/modules/core/filter_box_blur.c mlt-7.6.0/src/modules/core/filter_box_blur.c --- mlt-7.4.0/src/modules/core/filter_box_blur.c 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_box_blur.c 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,91 @@ +/* + * filter_box_blur.c + * Copyright (C) 2011-2021 Meltytech, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "image_proc.h" + +#include +#include +#include +#include + +#include + +static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) +{ + int error = 0; + mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); + mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); + mlt_position position = mlt_filter_get_position( filter, frame ); + mlt_position length = mlt_filter_get_length2( filter, frame ); + mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); + double hradius = mlt_properties_anim_get_double( properties, "hradius", position, length ); + double vradius = mlt_properties_anim_get_double( properties, "vradius", position, length ); + // Convert from percent to pixels as a factor of 10% image width. + double pixelScale = (double)profile->width * mlt_profile_scale_width( profile, *width ) / 1000.0; + hradius = MAX(round(hradius * pixelScale), 0); + vradius = MAX(round(vradius * pixelScale), 0); + + if ( hradius == 0 && vradius == 0 ) + { + // Nothing to blur + error = mlt_frame_get_image( frame, image, format, width, height, writable ); + } + else + { + // Get the image + *format = mlt_image_rgba; + error = mlt_frame_get_image( frame, image, format, width, height, 1 ); + if ( error == 0 ) + { + struct mlt_image_s img; + mlt_image_set_values( &img, *image, *format, *width, *height ); + mlt_image_box_blur( &img, hradius, vradius ); + } + } + return error; +} + +/** Filter processing. +*/ + +static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) +{ + mlt_frame_push_service( frame, filter ); + mlt_frame_push_get_image( frame, filter_get_image ); + + return frame; +} + +/** Constructor for the filter. +*/ + +mlt_filter filter_box_blur_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) +{ + mlt_filter filter = mlt_filter_new( ); + if ( filter != NULL ) + { + filter->process = filter_process; + mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "hradius", "1" ); + mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "vradius", "1" ); + } + return filter; +} + + + diff -Nru mlt-7.4.0/src/modules/core/filter_box_blur.yml mlt-7.6.0/src/modules/core/filter_box_blur.yml --- mlt-7.4.0/src/modules/core/filter_box_blur.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_box_blur.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,35 @@ +schema_version: 7.0 +type: filter +identifier: box_blur +title: Box Blur +version: 1 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +tags: + - Video +parameters: + + - identifier: hradius + title: Horizontal radius + description: > + The horizontal blur radius as a percent of the image size. + 100% results in a blur radius of 10% of the image width. + type: float + unit: percent + mutable: yes + animation: yes + minimum: 0 + default: 1 + + - identifier: vradius + title: Vertical radius + description: > + The vertical blur radius as a percent of the image size. + 100% results in a blur radius of 10% of the image width. + type: float + unit: percent + mutable: yes + animation: yes + minimum: 0 + default: 1 diff -Nru mlt-7.4.0/src/modules/core/filter_brightness.c mlt-7.6.0/src/modules/core/filter_brightness.c --- mlt-7.4.0/src/modules/core/filter_brightness.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_brightness.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_brightness.c -- brightness, fade, and opacity filter - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -32,15 +32,17 @@ mlt_image image; double level; double alpha_level; + int full_range; }; static int sliced_proc(int id, int index, int jobs, void* cookie) { (void) id; // unused struct sliced_desc* ctx = ((struct sliced_desc*) cookie); - int slice_height = (ctx->image->height + jobs - 1) / jobs; - int slice_line_start = index * slice_height; - slice_height = MIN(slice_height, ctx->image->height - slice_line_start); + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, ctx->image->height, &slice_line_start); + int min = ctx->full_range? 0 : 16; + int max_luma = ctx->full_range? 255 : 235; + int max_chroma = ctx->full_range? 255 : 240; // Only process if level is something other than 1 if (ctx->level != 1.0 && ctx->image->format == mlt_image_yuv422) { @@ -51,8 +53,8 @@ uint8_t* p = ctx->image->planes[0] + ( (slice_line_start + line) * ctx->image->strides[0]); for ( int pixel = 0; pixel < ctx->image->width; pixel++ ) { - *p++ = CLAMP((*p * m) >> 16, 16, 235); - *p++ = CLAMP((*p * m + n) >> 16, 16, 240); + *p++ = CLAMP((*p * m) >> 16, min, max_luma); + *p++ = CLAMP((*p * m + n) >> 16, min, max_chroma); } } @@ -150,6 +152,7 @@ desc.level = level; desc.alpha_level = alpha_level; desc.image = &proc_image; + desc.full_range = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), "full_range"); threads = CLAMP(threads, 0, mlt_slices_count_normal()); if (threads == 1) { diff -Nru mlt-7.4.0/src/modules/core/filter_brightness.yml mlt-7.6.0/src/modules/core/filter_brightness.yml --- mlt-7.4.0/src/modules/core/filter_brightness.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_brightness.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: brightness title: Brightness @@ -12,14 +12,14 @@ - Video parameters: - identifier: start - title: Start level (*deprecated*) + title: Start level (*DEPRECATED*) type: float argument: yes minimum: 0.0 maximum: 15.0 default: 1.0 - - identifier: end (*deprecated*) + - identifier: end (*DEPRECATED*) title: End level type: float minimum: 0.0 @@ -31,6 +31,8 @@ type: float minimum: 0.0 maximum: 15.0 + mutable: yes + animation: yes - identifier: alpha title: Alpha factor @@ -43,6 +45,7 @@ minimum: -1 maximum: 1 mutable: yes + animation: yes - identifier: threads title: Thread count diff -Nru mlt-7.4.0/src/modules/core/filter_choppy.yml mlt-7.6.0/src/modules/core/filter_choppy.yml --- mlt-7.4.0/src/modules/core/filter_choppy.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_choppy.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: choppy title: Choppy @@ -18,4 +18,5 @@ default: 0 minimum: 0 mutable: yes + animation: yes unit: frames diff -Nru mlt-7.4.0/src/modules/core/filter_crop.yml mlt-7.6.0/src/modules/core/filter_crop.yml --- mlt-7.4.0/src/modules/core/filter_crop.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_crop.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: crop title: Crop @@ -17,7 +17,8 @@ second instance of the filter may be applied to set the parameters of the crop operation. parameters: - - identifier: argument + - identifier: active + argument: yes title: Active description: Whether to do the processing (1) or simply set the parameters. type: integer diff -Nru mlt-7.4.0/src/modules/core/filter_fieldorder.c mlt-7.6.0/src/modules/core/filter_fieldorder.c --- mlt-7.4.0/src/modules/core/filter_fieldorder.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_fieldorder.c 2022-04-19 08:45:42.000000000 +0000 @@ -34,7 +34,7 @@ if ( !error && *image ) { - int tff = mlt_properties_get_int( properties, "consumer_tff" ); + int tff = mlt_properties_get_int( properties, "consumer.top_field_first" ); // Provides a manual override for misreported field order if ( mlt_properties_get( properties, "meta.top_field_first" ) ) diff -Nru mlt-7.4.0/src/modules/core/filter_gamma.yml mlt-7.6.0/src/modules/core/filter_gamma.yml --- mlt-7.4.0/src/modules/core/filter_gamma.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_gamma.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: gamma title: Gamma @@ -11,14 +11,11 @@ - Video description: Adjust image luma using a non-linear power-law curve. parameters: - - identifier: argument - title: Gamma - type: float - description: The exponential factor of the power-law curve - default: 1.0 - identifier: gamma + argument: yes title: Gamma type: float - description: See "argument" + description: The exponential factor of the power-law curve mutable: yes + animation: yes default: 1.0 diff -Nru mlt-7.4.0/src/modules/core/filter_imageconvert.yml mlt-7.6.0/src/modules/core/filter_imageconvert.yml --- mlt-7.4.0/src/modules/core/filter_imageconvert.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_imageconvert.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,16 @@ +schema_version: 7.0 +type: filter +identifier: imageconvert +title: Basic Image Converter +version: 1 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +tags: + - Video +description: Converts the colorspace and pixel format. +notes: > + This is not intended to be created directly. Rather, the loader producer + loads it if it is available to set the convert_image function pointer on frames. + This implementation is old and naive by assuming all YCbCr video is ITU-R BT.601 + and all RGB is sRGB. diff -Nru mlt-7.4.0/src/modules/core/filter_luma.yml mlt-7.6.0/src/modules/core/filter_luma.yml --- mlt-7.4.0/src/modules/core/filter_luma.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_luma.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: luma title: Wipe @@ -13,7 +13,8 @@ Applies a luma transition between the current and next frames. Useful for transitions from a slideshow created using producer pixbuf. parameters: - - identifier: argument + - identifier: resource + argument: yes title: File type: string description: The luma map file to be used for the transition diff -Nru mlt-7.4.0/src/modules/core/filter_mask_start.yml mlt-7.6.0/src/modules/core/filter_mask_start.yml --- mlt-7.4.0/src/modules/core/filter_mask_start.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_mask_start.yml 2022-04-19 08:45:42.000000000 +0000 @@ -2,7 +2,7 @@ type: filter identifier: mask_start title: Setup a filter mask -version: 2 +version: 3 copyright: Meltytech, LLC creator: Dan Dennedy license: LGPLv2.1 diff -Nru mlt-7.4.0/src/modules/core/filter_mirror.c mlt-7.6.0/src/modules/core/filter_mirror.c --- mlt-7.4.0/src/modules/core/filter_mirror.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_mirror.c 2022-04-19 08:45:42.000000000 +0000 @@ -20,130 +20,113 @@ #include #include #include +#include #include #include #include -/** Do it :-). -*/ +typedef struct { + mlt_image image; + char* mirror; + int reverse; +} slice_desc; -static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) +static int do_slice_proc(int id, int index, int jobs, void* data) { - struct mlt_image_s img; + (void) id; // unused + slice_desc* desc = (slice_desc*) data; + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, desc->image->height, &slice_line_start); + int slice_line_end = slice_line_start + slice_height; + int slice_line_start_half, slice_height_half = mlt_slices_size_slice(jobs, index, desc->image->height / 2, &slice_line_start_half); + int slice_line_end_half = slice_line_start_half + slice_height_half; + int uneven_w = ( desc->image->width % 2 ) * 2; int i; - // Pop the mirror filter from the stack - mlt_filter filter = mlt_frame_pop_service( frame ); - - // Get the mirror type - mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); - - // Get the properties - char *mirror = mlt_properties_get( properties, "mirror" ); - - // Determine if reverse is required - int reverse = mlt_properties_get_int( properties, "reverse" ); - - // Get the image - *format = mlt_image_yuv422; - int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); - - // If we have an image of the right colour space - if ( error == 0 && *format == mlt_image_yuv422 ) + if ( !strcmp( desc->mirror, "horizontal" ) ) { - mlt_image_set_values( &img, *image, *format, *width, *height ); - if ( mlt_frame_get_alpha( frame ) ) - { - img.planes[3] = mlt_frame_get_alpha( frame ); - img.strides[3] = img.width; - } - - if ( !strcmp( mirror, "horizontal" ) ) + for ( i = slice_line_start; i < slice_line_end; i++ ) { - int uneven_w = ( img.width % 2 ) * 2; - for ( i = 0; i < img.height; i ++ ) + uint8_t* p = desc->image->planes[0] + desc->image->strides[0] * i; + uint8_t* q = p + desc->image->width * 2; + if ( !desc->reverse ) { - uint8_t* p = img.planes[0] + img.strides[0] * i; - uint8_t* q = p + img.width * 2; - if ( !reverse ) + while ( p < q ) { - while ( p < q ) - { - *p ++ = *( q - 2 ); - *p ++ = *( q - 3 - uneven_w ); - *p ++ = *( q - 4 ); - *p ++ = *( q - 1 - uneven_w ); - q -= 4; - } + *p ++ = *( q - 2 ); + *p ++ = *( q - 3 - uneven_w ); + *p ++ = *( q - 4 ); + *p ++ = *( q - 1 - uneven_w ); + q -= 4; } - else + } + else + { + while ( p < q ) { - while ( p < q ) - { - *( q - 2 ) = *p ++; - *( q - 3 - uneven_w ) = *p ++; - *( q - 4 ) = *p ++; - *( q - 1 - uneven_w ) = *p ++; - q -= 4; - } + *( q - 2 ) = *p ++; + *( q - 3 - uneven_w ) = *p ++; + *( q - 4 ) = *p ++; + *( q - 1 - uneven_w ) = *p ++; + q -= 4; } } - if ( img.planes[3] ) + } + if ( desc->image->planes[3] ) + { + for ( i = slice_line_start; i < slice_line_end; i++ ) { - for ( i = 0; i < img.height; i ++ ) + uint8_t* a = desc->image->planes[3] + desc->image->strides[3] * i; + uint8_t* b = a + desc->image->width - 1; + if ( !desc->reverse ) { - uint8_t* a = img.planes[3] + img.strides[3] * i; - uint8_t* b = a + img.width - 1; - if ( !reverse ) + while ( a < b ) { - while ( a < b ) - { - *a ++ = *b --; - *a ++ = *b --; - } + *a ++ = *b --; + *a ++ = *b --; } - else + } + else + { + while ( a < b ) { - while ( a < b ) - { - *b -- = *a ++; - *b -- = *a ++; - } + *b -- = *a ++; + *b -- = *a ++; } } } - } - else if ( !strcmp( mirror, "vertical" ) ) + } + else if ( !strcmp( desc->mirror, "vertical" ) ) + { + for ( i = slice_line_start_half; i < slice_line_end_half; i ++ ) { - int hh = img.height / 2; - for ( i = 0; i < hh; i ++ ) + uint16_t* p = (uint16_t*)(desc->image->planes[0] + (desc->image->strides[0] * i)); + uint16_t* q = (uint16_t*)(desc->image->planes[0] + (desc->image->strides[0] * (desc->image->height - i - 1))); + int j = desc->image->width; + if ( !desc->reverse ) { - uint16_t* p = (uint16_t*)(img.planes[0] + (img.strides[0] * i)); - uint16_t* q = (uint16_t*)(img.planes[0] + (img.strides[0] * (img.height - i - 1))); - int j = img.width; - if ( !reverse ) + while ( j -- ) { - while ( j -- ) - { - *p ++ = *q ++; - } + *p ++ = *q ++; } - else + } + else + { + while ( j -- ) { - while ( j -- ) - { - *q ++ = *p ++; - } + *q ++ = *p ++; } } - if ( img.planes[3] ) + } + if ( desc->image->planes[3] ) + { + for ( i = slice_line_start_half; i < slice_line_end_half; i ++ ) { - int j = img.width; - uint8_t* a = img.planes[3] + (img.strides[3] * i); - uint8_t* b = img.planes[3] + (img.strides[3] * (img.height - i - 1)); - if ( !reverse ) + int j = desc->image->width; + uint8_t* a = desc->image->planes[3] + (desc->image->strides[3] * i); + uint8_t* b = desc->image->planes[3] + (desc->image->strides[3] * (desc->image->height - i - 1)); + if ( !desc->reverse ) while ( j -- ) *a ++ = *b ++; else @@ -151,175 +134,199 @@ *b ++ = *a ++; } } - else if ( !strcmp( mirror, "diagonal" ) ) + } + else if ( !strcmp( desc->mirror, "diagonal" ) ) + { + for ( i = slice_line_start; i < slice_line_end; i ++ ) { - int uneven_w = ( img.width % 2 ) * 2; - for ( i = 0; i < img.height; i ++ ) + uint8_t* p = desc->image->planes[0] + (desc->image->strides[0] * i); + uint8_t* q = desc->image->planes[0] + (desc->image->strides[0] * (desc->image->height - i - 1)); + int j = ( ( desc->image->width * ( desc->image->height - i ) ) / desc->image->height ) / 2; + if ( !desc->reverse ) { - uint8_t* p = img.planes[0] + (img.strides[0] * i); - uint8_t* q = img.planes[0] + (img.strides[0] * (img.height - i - 1)); - int j = ( ( img.width * ( img.height - i ) ) / img.height ) / 2; - if ( !reverse ) - { - while ( j -- ) - { - *p ++ = *( q - 2 ); - *p ++ = *( q - 3 - uneven_w ); - *p ++ = *( q - 4 ); - *p ++ = *( q - 1 - uneven_w ); - q -= 4; - } - } - else + while ( j -- ) { - while ( j -- ) - { - *( q - 2 ) = *p ++; - *( q - 3 - uneven_w ) = *p ++; - *( q - 4 ) = *p ++; - *( q - 1 - uneven_w ) = *p ++; - q -= 4; - } + *p ++ = *( q - 2 ); + *p ++ = *( q - 3 - uneven_w ); + *p ++ = *( q - 4 ); + *p ++ = *( q - 1 - uneven_w ); + q -= 4; } } - if ( img.planes[3] ) + else { - int i; - for ( i = 0; i < img.height; i ++ ) + while ( j -- ) { - int j = ( img.width * ( img.height - i ) ) / img.height; - uint8_t* a = img.planes[3] + (img.strides[3] * i); - uint8_t* b = img.planes[3] + (img.strides[3] * (img.height - i - 1)); - if ( !reverse ) - while ( j -- ) - *a ++ = *b --; - else - while ( j -- ) - *b -- = *a ++; + *( q - 2 ) = *p ++; + *( q - 3 - uneven_w ) = *p ++; + *( q - 4 ) = *p ++; + *( q - 1 - uneven_w ) = *p ++; + q -= 4; } } } - else if ( !strcmp( mirror, "xdiagonal" ) ) + if ( desc->image->planes[3] ) { - int uneven_w = ( img.width % 2 ) * 2; - for ( i = 0; i < img.height; i ++ ) + int i; + for ( i = slice_line_start; i < slice_line_end; i ++ ) { - uint8_t* p = img.planes[0] + (img.strides[0] * (i + 1)); - uint8_t* q = img.planes[0] + (img.strides[0] * (img.height - i)); - int j = ( ( img.width * ( img.height - i ) ) / img.height ) / 2; - if ( !reverse ) - { + int j = ( desc->image->width * ( desc->image->height - i ) ) / desc->image->height; + uint8_t* a = desc->image->planes[3] + (desc->image->strides[3] * i); + uint8_t* b = desc->image->planes[3] + (desc->image->strides[3] * (desc->image->height - i - 1)); + if ( !desc->reverse ) while ( j -- ) - { - *q ++ = *( p - 2 ); - *q ++ = *( p - 3 - uneven_w ); - *q ++ = *( p - 4 ); - *q ++ = *( p - 1 - uneven_w ); - p -= 4; - } - } + *a ++ = *b --; else - { while ( j -- ) - { - *( p - 2 ) = *q ++; - *( p - 3 - uneven_w ) = *q ++; - *( p - 4 ) = *q ++; - *( p - 1 - uneven_w ) = *q ++; - p -= 4; - } + *b -- = *a ++; + } + } + } + else if ( !strcmp( desc->mirror, "xdiagonal" ) ) + { + for ( i = slice_line_start; i < slice_line_end; i ++ ) + { + uint8_t* p = desc->image->planes[0] + (desc->image->strides[0] * (i + 1)); + uint8_t* q = desc->image->planes[0] + (desc->image->strides[0] * (desc->image->height - i)); + int j = ( ( desc->image->width * ( desc->image->height - i ) ) / desc->image->height ) / 2; + if ( !desc->reverse ) + { + while ( j -- ) + { + *q ++ = *( p - 2 ); + *q ++ = *( p - 3 - uneven_w ); + *q ++ = *( p - 4 ); + *q ++ = *( p - 1 - uneven_w ); + p -= 4; } } - if ( img.planes[3] ) + else { - int i; - for ( i = 0; i < img.height; i ++ ) + while ( j -- ) { - int j = ( ( img.width * ( img.height - i ) ) / img.height ); - uint8_t* a = img.planes[3] + (img.strides[3] * i) + img.width - 1; - uint8_t* b = img.planes[3] + (img.strides[3] * (img.height - i - 1)); - if ( !reverse ) - while ( j -- ) - *b ++ = *a --; - else - while ( j -- ) - *a -- = *b ++; + *( p - 2 ) = *q ++; + *( p - 3 - uneven_w ) = *q ++; + *( p - 4 ) = *q ++; + *( p - 1 - uneven_w ) = *q ++; + p -= 4; } } } - else if ( !strcmp( mirror, "flip" ) ) + if ( desc->image->planes[3] ) { - uint8_t t[ 4 ]; - int uneven_w = ( img.width % 2 ) * 2; - for ( i = 0; i < img.height; i ++ ) + int i; + for ( i = slice_line_start; i < slice_line_end; i ++ ) { - uint8_t* p = img.planes[0] + (img.strides[0] * i); - uint8_t* q = p + *width * 2; - while ( p < q ) - { - t[ 0 ] = p[ 0 ]; - t[ 1 ] = p[ 1 + uneven_w ]; - t[ 2 ] = p[ 2 ]; - t[ 3 ] = p[ 3 + uneven_w ]; - *p ++ = *( q - 2 ); - *p ++ = *( q - 3 - uneven_w ); - *p ++ = *( q - 4 ); - *p ++ = *( q - 1 - uneven_w ); - *( -- q ) = t[ 3 ]; - *( -- q ) = t[ 0 ]; - *( -- q ) = t[ 1 ]; - *( -- q ) = t[ 2 ]; - } + int j = ( ( desc->image->width * ( desc->image->height - i ) ) / desc->image->height ); + uint8_t* a = desc->image->planes[3] + (desc->image->strides[3] * i) + desc->image->width - 1; + uint8_t* b = desc->image->planes[3] + (desc->image->strides[3] * (desc->image->height - i - 1)); + if ( !desc->reverse ) + while ( j -- ) + *b ++ = *a --; + else + while ( j -- ) + *a -- = *b ++; + } + } + } + else if ( !strcmp( desc->mirror, "flip" ) ) + { + uint8_t t[ 4 ]; + for ( i = slice_line_start; i < slice_line_end; i ++ ) + { + uint8_t* p = desc->image->planes[0] + (desc->image->strides[0] * i); + uint8_t* q = p + desc->image->width * 2; + while ( p < q ) + { + t[ 0 ] = p[ 0 ]; + t[ 1 ] = p[ 1 + uneven_w ]; + t[ 2 ] = p[ 2 ]; + t[ 3 ] = p[ 3 + uneven_w ]; + *p ++ = *( q - 2 ); + *p ++ = *( q - 3 - uneven_w ); + *p ++ = *( q - 4 ); + *p ++ = *( q - 1 - uneven_w ); + *( -- q ) = t[ 3 ]; + *( -- q ) = t[ 0 ]; + *( -- q ) = t[ 1 ]; + *( -- q ) = t[ 2 ]; } - if ( img.planes[3] ) + } + if ( desc->image->planes[3] ) + { + uint8_t c; + for ( i = slice_line_start; i < slice_line_end; i ++ ) { - uint8_t c; - for ( i = 0; i < img.height; i ++ ) - { - uint8_t* a = img.planes[3] + (img.strides[3] * i); - uint8_t* b = a + img.width - 1; - while ( a < b ) - { - c = *a; - *a ++ = *b; - *b -- = c; - } + uint8_t* a = desc->image->planes[3] + (desc->image->strides[3] * i); + uint8_t* b = a + desc->image->width - 1; + while ( a < b ) + { + c = *a; + *a ++ = *b; + *b -- = c; } } } - else if ( !strcmp( mirror, "flop" ) ) + } + else if ( !strcmp( desc->mirror, "flop" ) ) + { + uint16_t t; + for ( i = slice_line_start_half; i < slice_line_end_half; i ++ ) { - uint16_t t; - int hh = *height / 2; - for ( i = 0; i < hh; i ++ ) - { - uint16_t* p = (uint16_t*)(img.planes[0] + (img.strides[0] * i)); - uint16_t* q = (uint16_t*)(img.planes[0] + (img.strides[0] * (img.height - i - 1))); - int j = img.width; - while ( j -- ) - { - t = *p; - *p ++ = *q; - *q ++ = t; - } + uint16_t* p = (uint16_t*)(desc->image->planes[0] + (desc->image->strides[0] * i)); + uint16_t* q = (uint16_t*)(desc->image->planes[0] + (desc->image->strides[0] * (desc->image->height - i - 1))); + int j = desc->image->width; + while ( j -- ) + { + t = *p; + *p ++ = *q; + *q ++ = t; } - if ( img.planes[3] ) + } + if ( desc->image->planes[3] ) + { + uint8_t c; + for ( i = slice_line_start_half; i < slice_line_end_half; i ++ ) { - uint8_t c; - for ( i = 0; i < img.height; i ++ ) - { - uint8_t* a = img.planes[3] + (img.strides[3] * i); - uint8_t* b = img.planes[3] + (img.strides[3] * (img.height - i - 1)); - while ( a < b ) - { - c = *a; - *a ++ = *b; - *b -- = c; - } + uint8_t* a = desc->image->planes[3] + (desc->image->strides[3] * i); + uint8_t* b = desc->image->planes[3] + (desc->image->strides[3] * (desc->image->height - i - 1)); + while ( a < b ) + { + c = *a; + *a ++ = *b; + *b -- = c; } } } } +} + +static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) +{ + // Pop the mirror filter from the stack + mlt_filter filter = mlt_frame_pop_service( frame ); + + // Get the image + *format = mlt_image_yuv422; + int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); + + // If we have an image of the right colour space + if ( error == 0 && *format == mlt_image_yuv422 ) + { + mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); + slice_desc desc; + struct mlt_image_s img; + mlt_image_set_values( &img, *image, *format, *width, *height ); + if ( mlt_frame_get_alpha( frame ) ) + { + img.planes[3] = mlt_frame_get_alpha( frame ); + img.strides[3] = img.width; + } + desc.image = &img; + desc.mirror = mlt_properties_get( properties, "mirror" ); + desc.reverse = mlt_properties_get_int( properties, "reverse" ); + mlt_slices_run_normal(0, do_slice_proc, &desc); + } // Return the error return error; diff -Nru mlt-7.4.0/src/modules/core/filter_mirror.yml mlt-7.6.0/src/modules/core/filter_mirror.yml --- mlt-7.4.0/src/modules/core/filter_mirror.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_mirror.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: mirror title: Mirror @@ -12,8 +12,9 @@ description: > Provides various mirror and image reversing effects. parameters: - - identifier: argument - title: File + - identifier: mirror + argument: yes + title: Mirror Type type: string description: Choose the type of mirror operation. values: diff -Nru mlt-7.4.0/src/modules/core/filter_mono.yml mlt-7.6.0/src/modules/core/filter_mono.yml --- mlt-7.4.0/src/modules/core/filter_mono.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_mono.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: mono title: Mixdown @@ -12,7 +12,8 @@ description: > Mix all channels of audio into a mono signal and output it as N channels. parameters: - - identifier: argument + - identifier: channels + argument: yes title: channels type: integer description: > diff -Nru mlt-7.4.0/src/modules/core/filter_obscure.yml mlt-7.6.0/src/modules/core/filter_obscure.yml --- mlt-7.4.0/src/modules/core/filter_obscure.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_obscure.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: obscure title: Obscure @@ -12,7 +12,8 @@ description: > Obscuring filter. parameters: - - identifier: argument + - identifier: start + argument: yes title: Start type: string description: > diff -Nru mlt-7.4.0/src/modules/core/filter_panner.yml mlt-7.6.0/src/modules/core/filter_panner.yml --- mlt-7.4.0/src/modules/core/filter_panner.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_panner.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.2 +schema_version: 7.0 type: filter identifier: panner title: Audio Pan @@ -21,7 +21,7 @@ If value for property "split" is set value of this property is discarded. type: float - argument: true + argument: yes mutable: yes minimum: 0 maximum: 1 @@ -70,5 +70,6 @@ If this value is set, values for properties "start" and "end" are discarded. type: float mutable: yes + animation: yes minimum: 0 maximum: 1 diff -Nru mlt-7.4.0/src/modules/core/filter_pillar_echo.c mlt-7.6.0/src/modules/core/filter_pillar_echo.c --- mlt-7.4.0/src/modules/core/filter_pillar_echo.c 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_pillar_echo.c 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,313 @@ +/* + * filter_pillar_echo.c -- filter to interpolate pixels outside an area of interest + * Copyright (c) 2020-2021 Meltytech, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "image_proc.h" + +#include +#include + +#include +#include + +/** Constrain a rect to be within the max dimensions +*/ +static mlt_rect constrain_rect( mlt_rect rect, int max_x, int max_y ) +{ + if ( rect.x < 0 ) + { + rect.w = rect.w + rect.x ; + rect.x = 0; + } + if ( rect.y < 0 ) + { + rect.h = rect.h + rect.y; + rect.y = 0; + } + if ( rect.x + rect.w < 0 ) + { + rect.w = 0; + } + if ( rect.y + rect.h < 0 ) + { + rect.h = 0; + } + if ( rect.x + rect.w > max_x ) + { + rect.w = max_x - rect.x; + } + if ( rect.y + rect.h > max_y ) + { + rect.h = max_y - rect.y; + } + return rect; +} + +typedef struct +{ + mlt_image src; + mlt_image dst; + mlt_rect rect; +} scale_sliced_desc; + +static int scale_sliced_proc(int id, int index, int jobs, void* data) +{ + (void) id; // unused + scale_sliced_desc* desc = ((scale_sliced_desc*) data); + mlt_image src = desc->src; + mlt_image dst = desc->dst; + mlt_rect rect = desc->rect; + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, src->height, &slice_line_start); + int slice_line_end = slice_line_start + slice_height; + double srcScale = rect.h / (double)src->height; + int linesize = src->width * 4; + uint8_t* d = dst->data + (slice_line_start * linesize); + for ( int y = slice_line_start; y < slice_line_end; y++ ) + { + double srcY = rect.y + (double)y * srcScale; + int srcYindex = floor(srcY); + double fbottom = srcY - srcYindex; + double ftop = 1.0 - fbottom; + + int x = 0; + for ( x = 0; x < src->width; x++ ) + { + double srcX = rect.x + (double)x * srcScale; + int srcXindex = floor(srcX); + double fright = srcX - srcXindex; + double fleft = 1.0 - fright; + + double valueSum[] = {0.0, 0.0, 0.0, 0.0}; + double factorSum[] = {0.0, 0.0, 0.0, 0.0}; + + uint8_t* s = src->data + (srcYindex * linesize) + (srcXindex * 4); + + // Top Left + double ftl = ftop * fleft; + valueSum[0] += s[0] * ftl; + factorSum[0] += ftl; + valueSum[1] += s[1] * ftl; + factorSum[1] += ftl; + valueSum[2] += s[2] * ftl; + factorSum[2] += ftl; + valueSum[3] += s[3] * ftl; + factorSum[3] += ftl; + + // Top Right + if ( x < src->width - 1 ) + { + double ftr = ftop * fright; + valueSum[0] += s[4] * ftr; + factorSum[0] += ftr; + valueSum[1] += s[5] * ftr; + factorSum[1] += ftr; + valueSum[2] += s[6] * ftr; + factorSum[2] += ftr; + valueSum[3] += s[7] * ftr; + factorSum[3] += ftr; + } + + if( y < src->height - 1 ) + { + uint8_t* sb = s + linesize; + + // Bottom Left + double fbl = fbottom * fleft; + valueSum[0] += sb[0] * fbl; + factorSum[0] += fbl; + valueSum[1] += sb[1] * fbl; + factorSum[1] += fbl; + valueSum[2] += sb[2] * fbl; + factorSum[2] += fbl; + valueSum[3] += sb[3] * fbl; + factorSum[3] += fbl; + + // Bottom Right + if ( x < src->width - 1 ) + { + double fbr = fbottom * fright; + valueSum[0] += sb[4] * fbr; + factorSum[0] += fbr; + valueSum[1] += sb[5] * fbr; + factorSum[1] += fbr; + valueSum[2] += sb[6] * fbr; + factorSum[2] += fbr; + valueSum[3] += sb[7] * fbr; + factorSum[3] += fbr; + } + } + + d[0] = (uint8_t)round( valueSum[0] / factorSum[0] ); + d[1] = (uint8_t)round( valueSum[1] / factorSum[1] ); + d[2] = (uint8_t)round( valueSum[2] / factorSum[2] ); + d[3] = (uint8_t)round( valueSum[3] / factorSum[3] ); + d += 4; + } + } +} + +/** Perform a bilinear scale from the rect inside the source to fill the destination + * + * \param src a pointer to the source image + * \param dst a pointer to the destination image + * \param rect the area of interest in the src to be scaled to fit the dst + */ + +static void bilinear_scale_rgba( mlt_image src, mlt_image dst, mlt_rect rect ) +{ + scale_sliced_desc desc; + desc.src = src; + desc.dst = dst; + desc.rect = rect; + + // Crop out a section of the rect that has the same aspect ratio as the image + double destAr = (double)src->width / (double)src->height; + double sourceAr = rect.w / rect.h; + if ( sourceAr > destAr ) + { + // Crop sides to fit height + desc.rect.w = rect.w * destAr / sourceAr; + desc.rect.x = rect.x + (rect.w - desc.rect.w) / 2.0; + } + else if ( destAr > sourceAr ) + { + // Crop top and bottom to fit width. + desc.rect.h = rect.h * sourceAr / destAr; + desc.rect.y = rect.y + (rect.h - desc.rect.h) / 2.0; + } + mlt_slices_run_normal(0, scale_sliced_proc, &desc); +} + + +/** Copy pixels from source to destination + * + * \param src a pointer to the source image + * \param dst a pointer to the destination image + * \param width the number of values in each row + * \param rect the area of interest in the src to be copied to the dst + */ + +static void blit_rect( mlt_image src, mlt_image dst, mlt_rect rect ) +{ + int blitHeight = rect.h; + int blitWidth = rect.w * 4; + int linesize = src->width * 4; + uint8_t* s = src->data + (int)rect.y * linesize + (int)rect.x * 4; + uint8_t* d = dst->data + (int)rect.y * linesize + (int)rect.x * 4; + while ( blitHeight-- ) + { + memcpy( d, s, blitWidth ); + s += linesize; + d += linesize; + } +} + +static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) +{ + int error = 0; + mlt_filter filter = (mlt_filter)mlt_frame_pop_service( frame ); + mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); + char* rect_str = mlt_properties_get( filter_properties, "rect" ); + if ( !rect_str ) + { + mlt_log_warning( MLT_FILTER_SERVICE(filter), "rect property not set\n" ); + return mlt_frame_get_image( frame, image, format, width, height, writable ); + } + mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); + mlt_position position = mlt_filter_get_position( filter, frame ); + mlt_position length = mlt_filter_get_length2( filter, frame ); + mlt_rect rect = mlt_properties_anim_get_rect( filter_properties, "rect", position, length ); + if ( strchr( rect_str, '%' ) ) + { + rect.x *= profile->width; + rect.w *= profile->width; + rect.y *= profile->height; + rect.h *= profile->height; + } + double scale = mlt_profile_scale_width( profile, *width ); + rect.x *= scale; + rect.w *= scale; + scale = mlt_profile_scale_height( profile, *height ); + rect.y *= scale; + rect.h *= scale; + rect = constrain_rect( rect, profile->width * scale, profile->height * scale ); + + if ( rect.w < 1 || rect.h < 1 ) + { + mlt_log_info( MLT_FILTER_SERVICE(filter), "rect invalid\n" ); + return mlt_frame_get_image( frame, image, format, width, height, writable ); + } + + *format = mlt_image_rgba; + error = mlt_frame_get_image( frame, image, format, width, height, 0 ); + + if (error) return error; + if (rect.x <= 0 && rect.y <= 0 && rect.w >= *width && rect.h >= *height) + { + // Rect fills the image. Nothing to blur + return error; + } + + double blur = mlt_properties_anim_get_double( filter_properties, "blur", position, length ); + // Convert from percent to pixels. + blur = blur * (double)profile->width * mlt_profile_scale_width( profile, *width ) / 100.0; + blur = MAX(round(blur), 0); + + struct mlt_image_s src; + mlt_image_set_values( &src, *image, *format, *width, *height ); + + struct mlt_image_s dst; + mlt_image_set_values( &dst, NULL, *format, *width, *height ); + mlt_image_alloc_data( &dst ); + + bilinear_scale_rgba( &src, &dst, rect ); + if (blur != 0) { + mlt_image_box_blur( &dst, blur, blur ); + } + blit_rect( &src, &dst, rect ); + + *image = dst.data; + mlt_frame_set_image( frame, dst.data, 0, dst.release_data ); + + return error; +} + +static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) +{ + mlt_frame_push_service( frame, filter ); + mlt_frame_push_get_image( frame, filter_get_image ); + return frame; +} + +mlt_filter filter_pillar_echo_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) +{ + mlt_filter filter = mlt_filter_new(); + + if ( filter ) + { + mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); + mlt_properties_set( properties, "rect", "0% 0% 10% 10%" ); + mlt_properties_set_double( properties, "blur", 4.0 ); + filter->process = filter_process; + } + else + { + mlt_log_error( NULL, "Filter pillar_echo initialization failed\n" ); + } + return filter; +} diff -Nru mlt-7.4.0/src/modules/core/filter_pillar_echo.yml mlt-7.6.0/src/modules/core/filter_pillar_echo.yml --- mlt-7.4.0/src/modules/core/filter_pillar_echo.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_pillar_echo.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,39 @@ +schema_version: 7.0 +type: filter +identifier: pillar_echo +title: Pillar Echo +version: 1 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +tags: + - Video +description: > + Create an echo effect (blur) outside of an area of interest. + + The area of interest is scaled to fill the image, then blurred. Then the + original image is replaced back on top. +parameters: + - identifier: rect + title: Rectangle + description: > + Defines the rectangle of the area of interest. + + Format is: "X Y W H". + + X, Y, W, H are assumed to be pixel units unless they have the suffix '%'. + type: rect + default: "0 0 10% 10%" + readonly: no + mutable: yes + animation: yes + + - identifier: blur + title: Blur + description: > + The blur radius as a percent of the image width + type: float + default: 4.0 + readonly: no + mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/core/filter_rescale.c mlt-7.6.0/src/modules/core/filter_rescale.c --- mlt-7.4.0/src/modules/core/filter_rescale.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_rescale.c 2022-04-19 08:45:42.000000000 +0000 @@ -172,7 +172,7 @@ int iheight = *height; int owidth = *width; int oheight = *height; - char *interps = mlt_properties_get( properties, "rescale.interp" ); + char *interps = mlt_properties_get( properties, "consumer.rescale" ); if ( mlt_properties_get( filter_properties, "factor" ) ) { @@ -185,7 +185,7 @@ if ( interps == NULL ) { interps = mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "interpolation" ); - mlt_properties_set( properties, "rescale.interp", interps ); + mlt_properties_set( properties, "consumer.rescale", interps ); } // If meta.media.width/height exist, we want that as minimum information @@ -211,7 +211,7 @@ // Deinterlace if height is changing to prevent fields mixing on interpolation // One exception: non-interpolated, integral scaling if ( iheight != oheight && ( strcmp( interps, "nearest" ) || ( iheight % oheight != 0 ) ) ) - mlt_properties_set_int( properties, "consumer_deinterlace", 1 ); + mlt_properties_set_int( properties, "consumer.progressive", 1 ); // Convert the image to yuv422 when using the local scaler if ( scaler_method == filter_scale ) @@ -221,7 +221,7 @@ mlt_frame_get_image( frame, image, format, &iwidth, &iheight, writable ); // Get rescale interpretation again, in case the producer wishes to override scaling - interps = mlt_properties_get( properties, "rescale.interp" ); + interps = mlt_properties_get( properties, "consumer.rescale" ); if ( *image && strcmp( interps, "none" ) && ( iwidth != owidth || iheight != oheight ) ) { diff -Nru mlt-7.4.0/src/modules/core/filter_rescale.yml mlt-7.6.0/src/modules/core/filter_rescale.yml --- mlt-7.4.0/src/modules/core/filter_rescale.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_rescale.yml 2022-04-19 08:45:42.000000000 +0000 @@ -23,4 +23,4 @@ bugs: - > It only implements a nearest neighbour scaling - it is used as the base - class for the gtkrescale and mcrescale filters. + class for the gtkrescale and swscale filters. diff -Nru mlt-7.4.0/src/modules/core/filter_resize.c mlt-7.6.0/src/modules/core/filter_resize.c --- mlt-7.4.0/src/modules/core/filter_resize.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_resize.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_resize.c -- resizing filter - * Copyright (C) 2003-2020 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -210,15 +210,8 @@ // Reset the aspect ratio mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio ); - // XXX: This is a hack, but it forces the force_full_luma to apply by doing a RGB - // conversion because range scaling only occurs on YUV->RGB. And we do it here, - // after the deinterlace filter, which only operates in YUV to avoid a YUV->RGB->YUV->?. - // Instead, it will go YUV->RGB->?. - if ( mlt_properties_get_int( properties, "force_full_luma" ) ) - *format = mlt_image_rgba; - - // Hmmm... - char *rescale = mlt_properties_get( properties, "rescale.interp" ); + // Skip scaling if requested + char *rescale = mlt_properties_get( properties, "consumer.rescale" ); if ( rescale != NULL && !strcmp( rescale, "none" ) ) return mlt_frame_get_image( frame, image, format, width, height, writable ); diff -Nru mlt-7.4.0/src/modules/core/filter_resize.yml mlt-7.6.0/src/modules/core/filter_resize.yml --- mlt-7.4.0/src/modules/core/filter_resize.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_resize.yml 2022-04-19 08:45:42.000000000 +0000 @@ -15,4 +15,4 @@ Normally resize is used to pad the producer's output to what the consumer has requested after an upstream rescale filter first scales the image to maximise usage of the image area. This filter is automatically invoked by the loader - as part of image normalisation. + as part of image normalization. diff -Nru mlt-7.4.0/src/modules/core/filter_transition.yml mlt-7.6.0/src/modules/core/filter_transition.yml --- mlt-7.4.0/src/modules/core/filter_transition.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_transition.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,7 +1,7 @@ schema_version: 0.2 type: filter identifier: transition -title: Transition as Filter (*deprecated*) +title: Transition as Filter (*DEPRECATED*) version: 1 copyright: Meltytech, LLC creator: Charles Yates diff -Nru mlt-7.4.0/src/modules/core/filter_watermark.c mlt-7.6.0/src/modules/core/filter_watermark.c --- mlt-7.4.0/src/modules/core/filter_watermark.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_watermark.c 2022-04-19 08:45:42.000000000 +0000 @@ -153,7 +153,7 @@ // Set the b frame to be in the same position and have same consumer requirements mlt_frame_set_position( b_frame, position ); - mlt_properties_set_int( b_props, "consumer_deinterlace", mlt_properties_get_int( a_props, "consumer_deinterlace" ) || mlt_properties_get_int( properties, "deinterlace" ) ); + mlt_properties_set_int( b_props, "consumer.progressive", mlt_properties_get_int( a_props, "consumer.progressive" ) || mlt_properties_get_int( properties, "deinterlace" ) ); // Check for the special case - no aspect ratio means no problem :-) if ( mlt_frame_get_aspect_ratio( b_frame ) == 0 ) @@ -185,14 +185,14 @@ char temp[ 132 ]; int count = 0; uint8_t *alpha = NULL; - const char *rescale = mlt_properties_get( a_props, "rescale.interp" ); + const char *rescale = mlt_properties_get( a_props, "consumer.rescale" ); if ( rescale == NULL || !strcmp( rescale, "none" ) ) rescale = "hyper"; mlt_transition_process( composite, b_frame, a_frame ); - mlt_properties_set_int( a_props, "consumer_deinterlace", 1 ); - mlt_properties_set_int( b_props, "consumer_deinterlace", 1 ); - mlt_properties_set( a_props, "rescale.interp", rescale ); - mlt_properties_set( b_props, "rescale.interp", rescale ); + mlt_properties_set_int( a_props, "consumer.progressive", 1 ); + mlt_properties_set_int( b_props, "consumer.progressive", 1 ); + mlt_properties_set( a_props, "consumer.rescale", rescale ); + mlt_properties_set( b_props, "consumer.rescale", rescale ); mlt_service_apply_filters( MLT_FILTER_SERVICE( filter ), b_frame, 0 ); error = mlt_frame_get_image( b_frame, image, format, width, height, 1 ); alpha = mlt_frame_get_alpha( b_frame ); diff -Nru mlt-7.4.0/src/modules/core/filter_watermark.yml mlt-7.6.0/src/modules/core/filter_watermark.yml --- mlt-7.4.0/src/modules/core/filter_watermark.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/filter_watermark.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: watermark title: Overlay @@ -29,7 +29,8 @@ melt clip.dv -filter watermark:logo.png parameters: - - identifier: argument + - identifier: resource + argument: yes title: File/URL type: string description: The file to overlay. diff -Nru mlt-7.4.0/src/modules/core/image_proc.c mlt-7.6.0/src/modules/core/image_proc.c --- mlt-7.4.0/src/modules/core/image_proc.c 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/core/image_proc.c 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2022 Meltytech, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "image_proc.h" + +#include +#include + +#include + +typedef struct +{ + mlt_image src; + mlt_image dst; + int radius; +} blur_slice_desc; + +static int blur_h_proc(int id, int index, int jobs, void* data) +{ + (void) id; // unused + blur_slice_desc* desc = ((blur_slice_desc*) data); + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, desc->src->height, &slice_line_start); + int slice_line_end = slice_line_start + slice_height; + int accumulator[] = {0, 0, 0, 0}; + int x = 0; + int y = 0; + int step = 4; + int linesize = step * desc->src->width; + int radius = desc->radius; + + if ( desc->radius > (desc->src->width / 2) ) + { + radius = desc->src->width / 2; + } + double diameter = (radius * 2) + 1; + + for ( y = slice_line_start; y < slice_line_end; y++ ) + { + uint8_t* first = desc->src->data + (y * linesize); + uint8_t* last = first + linesize - step; + uint8_t* s1 = first; + uint8_t* s2 = first; + uint8_t* d = desc->dst->data + (y * linesize); + accumulator[0] = first[0] * (radius + 1); + accumulator[1] = first[1] * (radius + 1); + accumulator[2] = first[2] * (radius + 1); + accumulator[3] = first[3] * (radius + 1); + + for ( x = 0; x < radius; x++ ) + { + accumulator[0] += s1[0]; + accumulator[1] += s1[1]; + accumulator[2] += s1[2]; + accumulator[3] += s1[3]; + s1 += step; + } + for ( x = 0; x <= radius; x++ ) + { + accumulator[0] += s1[0] - first[0]; + accumulator[1] += s1[1] - first[1]; + accumulator[2] += s1[2] - first[2]; + accumulator[3] += s1[3] - first[3]; + d[0] = lrint((double)accumulator[0] / diameter); + d[1] = lrint((double)accumulator[1] / diameter); + d[2] = lrint((double)accumulator[2] / diameter); + d[3] = lrint((double)accumulator[3] / diameter); + s1 += step; + d += step; + } + for ( x= radius + 1; x < desc->src->width - radius; x++) + { + accumulator[0] += s1[0] - s2[0]; + accumulator[1] += s1[1] - s2[1]; + accumulator[2] += s1[2] - s2[2]; + accumulator[3] += s1[3] - s2[3]; + d[0] = lrint((double)accumulator[0] / diameter); + d[1] = lrint((double)accumulator[1] / diameter); + d[2] = lrint((double)accumulator[2] / diameter); + d[3] = lrint((double)accumulator[3] / diameter); + s1 += step; + s2 += step; + d += step; + } + for ( x = desc->src->width - radius; x < desc->src->width; x++ ) + { + accumulator[0] += last[0] - s2[0]; + accumulator[1] += last[1] - s2[1]; + accumulator[2] += last[2] - s2[2]; + accumulator[3] += last[3] - s2[3]; + d[0] = lrint((double)accumulator[0] / diameter); + d[1] = lrint((double)accumulator[1] / diameter); + d[2] = lrint((double)accumulator[2] / diameter); + d[3] = lrint((double)accumulator[3] / diameter); + s2 += step; + d += step; + } + } + return 0; +} + +static int blur_v_proc(int id, int index, int jobs, void* data) +{ + (void) id; // unused + blur_slice_desc* desc = ((blur_slice_desc*) data); + int slice_row_start, slice_width = mlt_slices_size_slice(jobs, index, desc->src->width, &slice_row_start); + int slice_row_end = slice_row_start + slice_width; + int accumulator[] = {0, 0, 0, 0}; + int x = 0; + int y = 0; + int step = 4; + int linesize = step * desc->src->width; + int radius = desc->radius; + + if ( desc->radius > (desc->src->height / 2) ) + { + radius = desc->src->height / 2; + } + double diameter = (radius * 2) + 1; + + for ( x = slice_row_start; x < slice_row_end; x++ ) + { + uint8_t* first = desc->src->data + (x * step); + uint8_t* last = first + (linesize * (desc->src->height - 1)); + uint8_t* s1 = first; + uint8_t* s2 = first; + uint8_t* d = desc->dst->data + (x * step); + accumulator[0] = first[0] * (radius + 1); + accumulator[1] = first[1] * (radius + 1); + accumulator[2] = first[2] * (radius + 1); + accumulator[3] = first[3] * (radius + 1); + + for ( y = 0; y < radius; y++ ) + { + accumulator[0] += s1[0]; + accumulator[1] += s1[1]; + accumulator[2] += s1[2]; + accumulator[3] += s1[3]; + s1 += linesize; + } + for ( y = 0; y <= radius; y++ ) + { + accumulator[0] += s1[0] - first[0]; + accumulator[1] += s1[1] - first[1]; + accumulator[2] += s1[2] - first[2]; + accumulator[3] += s1[3] - first[3]; + d[0] = lrint((double)accumulator[0] / diameter); + d[1] = lrint((double)accumulator[1] / diameter); + d[2] = lrint((double)accumulator[2] / diameter); + d[3] = lrint((double)accumulator[3] / diameter); + s1 += linesize; + d += linesize; + } + for ( y = radius + 1; y < desc->src->height - radius; y++) + { + accumulator[0] += s1[0] - s2[0]; + accumulator[1] += s1[1] - s2[1]; + accumulator[2] += s1[2] - s2[2]; + accumulator[3] += s1[3] - s2[3]; + d[0] = lrint((double)accumulator[0] / diameter); + d[1] = lrint((double)accumulator[1] / diameter); + d[2] = lrint((double)accumulator[2] / diameter); + d[3] = lrint((double)accumulator[3] / diameter); + s1 += linesize; + s2 += linesize; + d += linesize; + } + for ( y = desc->src->height - radius; y < desc->src->height; y++ ) + { + accumulator[0] += last[0] - s2[0]; + accumulator[1] += last[1] - s2[1]; + accumulator[2] += last[2] - s2[2]; + accumulator[3] += last[3] - s2[3]; + d[0] = lrint((double)accumulator[0] / diameter); + d[1] = lrint((double)accumulator[1] / diameter); + d[2] = lrint((double)accumulator[2] / diameter); + d[3] = lrint((double)accumulator[3] / diameter); + s2 += linesize; + d += linesize; + } + } + return 0; +} + +/** Perform a box blur + * + * This function uses a sliding window accumulator method - applied + * horizontally first and then vertically. + * + * \param self the Image object + * \param hradius the radius of the horizontal blur in pixels + * \param vradius radius of the vertical blur in pixels + */ + +void mlt_image_box_blur( mlt_image self, int hradius, int vradius ) +{ + if (self->format != mlt_image_rgba) { + mlt_log( NULL, MLT_LOG_ERROR, "Image type %s not supported by box blur\n", mlt_image_format_name( self->format ) ); + return; + } + // The horizontal blur is performed into a temporary image. + // The vertical blur is performed back into the original image. + struct mlt_image_s tmpimage; + mlt_image_set_values( &tmpimage, NULL, self->format, self->width, self->height ); + mlt_image_alloc_data( &tmpimage ); + if (self->alpha) + { + mlt_image_alloc_alpha( &tmpimage ); + } + + blur_slice_desc desc; + desc.src = self, + desc.dst = &tmpimage, + desc.radius = hradius, + mlt_slices_run_normal(0, blur_h_proc, &desc); + desc.src = &tmpimage, + desc.dst = self, + desc.radius = vradius, + mlt_slices_run_normal(0, blur_v_proc, &desc); + + mlt_image_close( &tmpimage ); +} diff -Nru mlt-7.4.0/src/modules/core/image_proc.h mlt-7.6.0/src/modules/core/image_proc.h --- mlt-7.4.0/src/modules/core/image_proc.h 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/core/image_proc.h 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 Meltytech, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef IMAGE_PROC_H +#define IMAGE_PROC_H + +#include +#include + +void mlt_image_box_blur( mlt_image self, int hradius, int vradius ); + +#endif // IMAGE_PROC_H diff -Nru mlt-7.4.0/src/modules/core/producer_abnormal.yml mlt-7.6.0/src/modules/core/producer_abnormal.yml --- mlt-7.4.0/src/modules/core/producer_abnormal.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/core/producer_abnormal.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,24 @@ +schema_version: 7.0 +type: filter +identifier: abnormal +title: Loader Without Normalization Filters +version: 1 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +tags: + - Audio + - Video + - Hidden +description: > + This is just like the loader producer except it does not add normalizing filters. + +parameters: + - identifier: resource + title: File/URL + type: string + description: The file for the producer to be based on. + argument: yes + required: yes + readonly: yes + widget: fileopen diff -Nru mlt-7.4.0/src/modules/core/producer_consumer.c mlt-7.6.0/src/modules/core/producer_consumer.c --- mlt-7.4.0/src/modules/core/producer_consumer.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/producer_consumer.c 2022-04-19 08:45:42.000000000 +0000 @@ -172,7 +172,7 @@ mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( cx->consumer ), "real_time", mlt_properties_get_int( properties, "real_time" ) ); mlt_properties_pass_list( MLT_CONSUMER_PROPERTIES( cx->consumer ), properties, - "buffer, prefill, deinterlace_method, rescale" ); + "buffer, prefill, deinterlacer, deinterlace_method, rescale" ); mlt_properties_pass( MLT_CONSUMER_PROPERTIES( cx->consumer ), properties, CONSUMER_PROPERTIES_PREFIX ); mlt_properties_pass( MLT_PRODUCER_PROPERTIES( cx->producer ), properties, PRODUCER_PROPERTIES_PREFIX ); diff -Nru mlt-7.4.0/src/modules/core/producer_consumer.yml mlt-7.6.0/src/modules/core/producer_consumer.yml --- mlt-7.4.0/src/modules/core/producer_consumer.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/producer_consumer.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: producer identifier: consumer title: Consumer as Producer @@ -11,7 +11,8 @@ - Audio - Video parameters: - - identifier: argument + - identifier: resource + argument: yes title: File/URL type: string description: A file name, URL, or producer name. diff -Nru mlt-7.4.0/src/modules/core/producer_hold.c mlt-7.6.0/src/modules/core/producer_hold.c --- mlt-7.4.0/src/modules/core/producer_hold.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/producer_hold.c 2022-04-19 08:45:42.000000000 +0000 @@ -96,7 +96,7 @@ mlt_properties_pass( MLT_FRAME_PROPERTIES( real_frame ), properties, "" ); // We'll deinterlace on the downstream deinterlacer - mlt_properties_set_int( MLT_FRAME_PROPERTIES( real_frame ), "consumer_deinterlace", 1 ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( real_frame ), "consumer.progressive", 1 ); // We want distorted to ensure we don't hit the resize filter twice mlt_properties_set_int( MLT_FRAME_PROPERTIES( real_frame ), "distort", 1 ); @@ -179,7 +179,7 @@ // Ensure that the consumer sees what the real frame has mlt_properties_pass( MLT_FRAME_PROPERTIES( *frame ), MLT_FRAME_PROPERTIES( real_frame ), "" ); - mlt_properties_set( MLT_FRAME_PROPERTIES( real_frame ), "deinterlace_method", + mlt_properties_set( MLT_FRAME_PROPERTIES( real_frame ), "consumer.deinterlacer", mlt_properties_get( properties, "method" ) ); } diff -Nru mlt-7.4.0/src/modules/core/producer_loader.yml mlt-7.6.0/src/modules/core/producer_loader.yml --- mlt-7.4.0/src/modules/core/producer_loader.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/producer_loader.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: producer identifier: loader title: Loader @@ -16,16 +16,18 @@ 1. it handles the mappings of all file names to the other producers; - 2. it attaches normalising filters (rescale, resize and resample) to the + 2. it attaches normalizing filters (rescale, resize and resample) to the producers (when necessary). This producer simplifies many aspects of use. Essentially, it ensures that a consumer will receive images and audio precisely as they request them. + parameters: - - identifier: argument + - identifier: resource title: File/URL type: string description: The file for the producer to be based on. - required: no - readonly: no + argument: yes + required: yes + readonly: yes widget: fileopen diff -Nru mlt-7.4.0/src/modules/core/transition_composite.c mlt-7.6.0/src/modules/core/transition_composite.c --- mlt-7.4.0/src/modules/core/transition_composite.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/transition_composite.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * transition_composite.c -- compose one image over another using alpha channel - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -237,7 +237,7 @@ static int sliced_composite_proc( int id, int idx, int jobs, void* cookie ) { struct sliced_composite_desc ctx = *((struct sliced_composite_desc*)cookie); - int i, hs = (ctx.height_src + jobs / 2) / jobs, ho = hs * idx; + int i, ho, hs = mlt_slices_size_slice(jobs, idx, ctx.height_src, &ho); for ( i = 0; i < ctx.height_src; i += ctx.step ) { @@ -574,7 +574,7 @@ mlt_image_format luma_format = mlt_image_yuv422; // Get image from the luma producer - mlt_properties_set( MLT_FRAME_PROPERTIES( luma_frame ), "rescale.interp", "none" ); + mlt_properties_set( MLT_FRAME_PROPERTIES( luma_frame ), "consumer.rescale", "none" ); mlt_frame_get_image( luma_frame, &luma_image, &luma_format, &luma_width, &luma_height, 0 ); // Generate the luma map @@ -928,8 +928,8 @@ // Manual option to deinterlace if ( mlt_properties_get_int( properties, "deinterlace" ) ) { - mlt_properties_set_int( a_props, "consumer_deinterlace", 1 ); - mlt_properties_set_int( b_props, "consumer_deinterlace", 1 ); + mlt_properties_set_int( a_props, "consumer.progressive", 1 ); + mlt_properties_set_int( b_props, "consumer.progressive", 1 ); } // TODO: Dangerous/temporary optimisation - if nothing to do, then do nothing @@ -975,8 +975,8 @@ // Special case for titling... if ( mlt_properties_get_int( properties, "titles" ) ) { - if ( mlt_properties_get( b_props, "rescale.interp" ) == NULL ) - mlt_properties_set( b_props, "rescale.interp", "hyper" ); + if ( mlt_properties_get( b_props, "consumer.rescale" ) == NULL ) + mlt_properties_set( b_props, "consumer.rescale", "hyper" ); width_b = mlt_properties_get_int( a_props, "dest_width" ); height_b = mlt_properties_get_int( a_props, "dest_height" ); } @@ -985,7 +985,7 @@ get_b_frame_image( self, b_frame, &image_b, &width_b, &height_b, &result ) ) ) { int progressive = - mlt_properties_get_int( a_props, "consumer_deinterlace" ) || + mlt_properties_get_int( a_props, "consumer.progressive" ) || mlt_properties_get_int( properties, "progressive" ); int top_field_first = mlt_properties_get_int( a_props, "top_field_first" ); int field; diff -Nru mlt-7.4.0/src/modules/core/transition_composite.yml mlt-7.6.0/src/modules/core/transition_composite.yml --- mlt-7.4.0/src/modules/core/transition_composite.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/transition_composite.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.3 +schema_version: 7.0 type: transition identifier: composite title: Composite @@ -31,10 +31,12 @@ default: loader - identifier: geometry + argument: yes title: Geometry type: rect description: A possibly keyframed rectangle mutable: yes + animation: yes - identifier: progressive title: Progressive @@ -153,3 +155,10 @@ default: 1 mutable: yes widget: checkbox + + - identifier: crop + title: Crop Rectangle + type: rect + description: Defines a cropping rectangle for the second input + mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/core/transition_luma.c mlt-7.6.0/src/modules/core/transition_luma.c --- mlt-7.4.0/src/modules/core/transition_luma.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/transition_luma.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * transition_luma.c -- a generic dissolve/wipe processor - * Copyright (C) 2003-2020 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * Adapted from Kino Plugin Timfx, which is * Copyright (C) 2002 Timothy M. Shead @@ -85,14 +85,13 @@ { struct dissolve_slice_context ctx = *((struct dissolve_slice_context*) context); int stride = ctx.width * 2; - int slice_height = (ctx.height + count - 1) / count; + int slice_start, slice_height = mlt_slices_size_slice(count, index, ctx.height, &slice_start); int i; - ctx.dst_image += index * slice_height * stride; - ctx.src_image += index * slice_height * stride; - if (ctx.dst_alpha) ctx.dst_alpha += index * slice_height * ctx.width; - if (ctx.src_alpha) ctx.src_alpha += index * slice_height * ctx.width; - slice_height = MIN(slice_height, ctx.height - index * slice_height); + ctx.dst_image += slice_start * stride; + ctx.src_image += slice_start * stride; + if (ctx.dst_alpha) ctx.dst_alpha += slice_start * ctx.width; + if (ctx.src_alpha) ctx.src_alpha += slice_start * ctx.width; for (i = 0; i < slice_height; i++) { composite_line_yuv_float( ctx.dst_image, ctx.src_image, ctx.width, ctx.src_alpha, ctx.dst_alpha, ctx.weight ); @@ -471,7 +470,7 @@ if (luma_image) { if (is_clip) { yuv422_to_luma16(luma_image, &luma_bitmap, luma_width, luma_height, - mlt_properties_get_int(MLT_FRAME_PROPERTIES(luma_frame), "full_luma")); + mlt_properties_get_int(MLT_FRAME_PROPERTIES(luma_frame), "full_range")); } else { mlt_luma_map_from_yuv422(luma_image, &luma_bitmap, luma_width, luma_height); } @@ -503,7 +502,7 @@ float frame_delta = mlt_transition_get_progress_delta( transition, a_frame ); float luma_softness = mlt_properties_get_double( properties, "softness" ); int progressive = - mlt_properties_get_int( a_props, "consumer_deinterlace" ) || + mlt_properties_get_int( a_props, "consumer.progressive" ) || mlt_properties_get_int( properties, "progressive" ) || mlt_properties_get_int( b_props, "luma.progressive" ); int top_field_first = mlt_properties_get_int( b_props, "top_field_first" ); diff -Nru mlt-7.4.0/src/modules/core/transition_matte.yml mlt-7.6.0/src/modules/core/transition_matte.yml --- mlt-7.4.0/src/modules/core/transition_matte.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/core/transition_matte.yml 2022-04-19 08:45:42.000000000 +0000 @@ -14,7 +14,7 @@ notes: | Please note that the transition automatically detects if the frame from track B has scaled or non-scaled luma. The frame property - "full_luma" should indicate it. + "full_range" should indicate it. If you need to prepare fill and key (matte) files, you can use melt or ffmpeg to extract alpha channel from existing video: diff -Nru mlt-7.4.0/src/modules/decklink/consumer_decklink.cpp mlt-7.6.0/src/modules/decklink/consumer_decklink.cpp --- mlt-7.4.0/src/modules/decklink/consumer_decklink.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/decklink/consumer_decklink.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -999,7 +999,7 @@ consumer->start = start; consumer->stop = stop; consumer->is_stopped = is_stopped; - mlt_properties_set( properties, "deinterlace_method", "onefield" ); + mlt_properties_set( properties, "consumer.deinterlacer", "onefield" ); mlt_event event = mlt_events_listen( properties, properties, "property-changed", (mlt_listener) on_property_changed ); mlt_properties_set_data( properties, "list-devices-event", event, 0, NULL, NULL ); diff -Nru mlt-7.4.0/src/modules/decklink/consumer_decklink.yml mlt-7.6.0/src/modules/decklink/consumer_decklink.yml --- mlt-7.4.0/src/modules/decklink/consumer_decklink.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/decklink/consumer_decklink.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.2 +schema_version: 7.0 type: consumer identifier: decklink title: Blackmagic Design DeckLink Output @@ -20,7 +20,8 @@ - Only internal keying is supported at this time. - Only 8-bit Y'CbCr or RGBA (key) is supported at this time. parameters: - - identifier: argument + - identifier: resource + argument: yes title: Card type: integer readonly: no diff -Nru mlt-7.4.0/src/modules/decklink/producer_decklink.cpp mlt-7.6.0/src/modules/decklink/producer_decklink.cpp --- mlt-7.4.0/src/modules/decklink/producer_decklink.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/decklink/producer_decklink.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * producer_decklink.c -- input from Blackmagic Design DeckLink - * Copyright (C) 2011-2021 Meltytech, LLC + * Copyright (C) 2011-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -47,9 +47,7 @@ int c, H, Y, i; struct copy_lines_sliced_desc *ctx = (struct copy_lines_sliced_desc*)cookie; - H = ( ctx->h + jobs ) / jobs; - Y = idx * H; - H = MIN( H, ctx->h - Y ); + H = mlt_slices_size_slice(jobs, idx, ctx->h, &Y); if ( ctx->in_fmt == bmdFormat10BitYUV ) // bmdFormat10BitYUV -> mlt_image_yuv422p16 { diff -Nru mlt-7.4.0/src/modules/decklink/producer_decklink.yml mlt-7.6.0/src/modules/decklink/producer_decklink.yml --- mlt-7.4.0/src/modules/decklink/producer_decklink.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/decklink/producer_decklink.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: producer identifier: decklink title: Blackmagic Design DeckLink Capture @@ -25,7 +25,8 @@ - External deck control is not implemented. - Only 8-bit Y'CbCr is supported at this time. parameters: - - identifier: argument + - identifier: resource + argument: yes title: Card type: integer default: 0 diff -Nru mlt-7.4.0/src/modules/frei0r/factory.c mlt-7.6.0/src/modules/frei0r/factory.c --- mlt-7.4.0/src/modules/frei0r/factory.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/frei0r/factory.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,7 +1,7 @@ /* * factory.c -- the factory method interfaces * Copyright (c) 2008 Marco Gittler - * Copyright (C) 2009-2020 Meltytech, LLC + * Copyright (C) 2009-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -148,7 +148,7 @@ } plginfo(&info); snprintf(string, sizeof(string) , "%d" , info.minor_version); - mlt_properties_set_double(metadata, "schema_version", 0.3); + mlt_properties_set(metadata, "schema_version", "7.0"); mlt_properties_set(metadata, "title" , info.name); mlt_properties_set_double(metadata, "version", info.major_version + info.minor_version / pow(10, strlen(string))); @@ -193,6 +193,7 @@ f0r_get_param_value(instance, &deflt, j); mlt_properties_set_double(pnum, "default", CLAMP(deflt, 0.0, 1.0)); mlt_properties_set(pnum, "mutable", "yes" ); + mlt_properties_set(pnum, "animation", "yes" ); mlt_properties_set(pnum, "widget", "spinner"); } else if (paraminfo.type == F0R_PARAM_BOOL) { double deflt = 0; @@ -202,6 +203,7 @@ f0r_get_param_value(instance, &deflt, j); mlt_properties_set_int(pnum, "default", deflt != 0.0); mlt_properties_set(pnum, "mutable", "yes"); + mlt_properties_set(pnum, "animation", "yes" ); mlt_properties_set(pnum, "widget", "checkbox"); } else if (paraminfo.type == F0R_PARAM_COLOR) { char colorstr[8]; diff -Nru mlt-7.4.0/src/modules/gdk/factory.c mlt-7.6.0/src/modules/gdk/factory.c --- mlt-7.4.0/src/modules/gdk/factory.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/gdk/factory.c 2022-04-19 08:45:42.000000000 +0000 @@ -81,7 +81,7 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; - snprintf( file, PATH_MAX, "%s/gtk2/%s", mlt_environment( "MLT_DATA" ), (char*) data ); + snprintf( file, PATH_MAX, "%s/gdk/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } diff -Nru mlt-7.4.0/src/modules/gdk/filter_rescale.c mlt-7.6.0/src/modules/gdk/filter_rescale.c --- mlt-7.4.0/src/modules/gdk/filter_rescale.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/gdk/filter_rescale.c 2022-04-19 08:45:42.000000000 +0000 @@ -34,7 +34,7 @@ mlt_properties properties = MLT_FRAME_PROPERTIES( this ); // Get the requested interpolation method - char *interps = mlt_properties_get( properties, "rescale.interp" ); + char *interps = mlt_properties_get( properties, "consumer.rescale" ); // Convert to the GTK flag int interp = PIXOPS_INTERP_BILINEAR; diff -Nru mlt-7.4.0/src/modules/gdk/filter_rescale.yml mlt-7.6.0/src/modules/gdk/filter_rescale.yml --- mlt-7.4.0/src/modules/gdk/filter_rescale.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/gdk/filter_rescale.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: gtkrescale title: Gtk Rescale @@ -21,7 +21,8 @@ disabled by another service by either removing the property, setting it to zero, or setting frame property "distort" to 1. parameters: - - identifier: argument + - identifier: interpolation + argument: yes title: Interpolation type: string description: The rescaling method. diff -Nru mlt-7.4.0/src/modules/gdk/producer_pango.c mlt-7.6.0/src/modules/gdk/producer_pango.c --- mlt-7.4.0/src/modules/gdk/producer_pango.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/gdk/producer_pango.c 2022-04-19 08:45:42.000000000 +0000 @@ -546,7 +546,7 @@ // If we have a pixbuf and a valid width if ( pixbuf && width > 0 ) { - char *interps = mlt_properties_get( properties, "rescale.interp" ); + char *interps = mlt_properties_get( properties, "consumer.rescale" ); int interp = GDK_INTERP_BILINEAR; if ( strcmp( interps, "nearest" ) == 0 ) diff -Nru mlt-7.4.0/src/modules/gdk/producer_pixbuf.c mlt-7.6.0/src/modules/gdk/producer_pixbuf.c --- mlt-7.4.0/src/modules/gdk/producer_pixbuf.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/gdk/producer_pixbuf.c 2022-04-19 08:45:42.000000000 +0000 @@ -579,7 +579,7 @@ // If we have a pixbuf and we need an image if ( self->pixbuf && ( !self->image || ( format != mlt_image_none && format != mlt_image_movit && format != self->format ) ) ) { - char *interps = mlt_properties_get( properties, "rescale.interp" ); + char *interps = mlt_properties_get( properties, "consumer.rescale" ); if ( interps ) interps = strdup( interps ); int interp = GDK_INTERP_BILINEAR; diff -Nru mlt-7.4.0/src/modules/jackrack/consumer_jack.c mlt-7.6.0/src/modules/jackrack/consumer_jack.c --- mlt-7.4.0/src/modules/jackrack/consumer_jack.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/jackrack/consumer_jack.c 2022-04-19 08:45:42.000000000 +0000 @@ -104,7 +104,7 @@ // Default scaler (for now we'll use nearest) mlt_properties_set( properties, "rescale", "nearest" ); - mlt_properties_set( properties, "deinterlace_method", "onefield" ); + mlt_properties_set( properties, "consumer.deinterlacer", "onefield" ); // Default buffer for low latency mlt_properties_set_int( properties, "buffer", 1 ); diff -Nru mlt-7.4.0/src/modules/jackrack/factory.c mlt-7.6.0/src/modules/jackrack/factory.c --- mlt-7.4.0/src/modules/jackrack/factory.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/jackrack/factory.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * factory.c -- the factory method interfaces - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * 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 @@ -83,6 +83,8 @@ } if ( LADSPA_IS_HINT_LOGARITHMIC( hint_descriptor ) ) mlt_properties_set( p, "scale", "log" ); + mlt_properties_set( p, "mutable", "yes" ); + mlt_properties_set( p, "animation", "yes" ); } #endif @@ -172,6 +174,7 @@ mlt_properties_set_double( p, "minimum", 0 ); mlt_properties_set_double( p, "maximum", 1 ); mlt_properties_set( p, "mutable", "yes" ); + mlt_properties_set( p, "animation", "yes" ); } } } @@ -210,6 +213,7 @@ # ifdef WITH_JACK MLT_REGISTER( mlt_service_filter_type, "jack", filter_jackrack_init ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "jack", metadata, "filter_jack.yml" ); MLT_REGISTER( mlt_service_filter_type, "jackrack", filter_jackrack_init ); MLT_REGISTER_METADATA( mlt_service_filter_type, "jackrack", metadata, "filter_jackrack.yml" ); # endif diff -Nru mlt-7.4.0/src/modules/jackrack/filter_jack.yml mlt-7.6.0/src/modules/jackrack/filter_jack.yml --- mlt-7.4.0/src/modules/jackrack/filter_jack.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/jackrack/filter_jack.yml 2022-04-19 08:45:42.000000000 +0000 @@ -51,7 +51,7 @@ - identifier: in_2 title: Receive R type: string - + - identifier: out_1 title: Send L type: string diff -Nru mlt-7.4.0/src/modules/jackrack/filter_ladspa.yml mlt-7.6.0/src/modules/jackrack/filter_ladspa.yml --- mlt-7.4.0/src/modules/jackrack/filter_ladspa.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/jackrack/filter_ladspa.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,9 +1,8 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: ladspa title: LADSPA version: 1 -copyright: Copyright (C) 2004-2014 Meltytech, LLC license: GPLv2 language: en url: http://www.ladspa.org/ @@ -17,7 +16,8 @@ - Some effects have a temporal side-effect that may not work well. parameters: - - identifier: argument + - identifier: resource + argument: yes title: JACK Rack XML file type: string description: > diff -Nru mlt-7.4.0/src/modules/jackrack/producer_ladspa.yml mlt-7.6.0/src/modules/jackrack/producer_ladspa.yml --- mlt-7.4.0/src/modules/jackrack/producer_ladspa.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/jackrack/producer_ladspa.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,9 +1,8 @@ -schema_version: 0.1 +schema_version: 7.0 type: producer identifier: ladspa title: LADSPA version: 1 -copyright: Copyright (C) 2013-2014 Meltytech, LLC license: GPLv2 language: en tags: diff -Nru mlt-7.4.0/src/modules/kdenlive/filter_boxblur.yml mlt-7.6.0/src/modules/kdenlive/filter_boxblur.yml --- mlt-7.4.0/src/modules/kdenlive/filter_boxblur.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/kdenlive/filter_boxblur.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,16 +1,18 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: boxblur -title: Box Blur +title: Box Blur (*DEPRECATED*) version: 3 copyright: Leny Grisel, Jean-Baptiste Mardelle creator: Leny Grisel, Jean-Baptiste Mardelle license: LGPLv2.1 language: en +notes: > + This filter is deprecated and will eventually be removed. Use the box_blur filter instead. tags: - Video parameters: - - identifier: start (*deprecated*) + - identifier: start (*DEPRECATED*) title: Size argument: yes type: integer @@ -28,7 +30,7 @@ default: 2 minimum: 1 - - identifier: end (*deprecated*) + - identifier: end (*DEPRECATED*) title: End size type: integer unit: pixels @@ -42,6 +44,7 @@ If this value is set the start and end parameters are ignored. unit: pixels mutable: yes + animation: yes minimum: 1 - identifier: hori @@ -49,6 +52,7 @@ type: integer unit: pixels mutable: yes + animation: yes minimum: 0 default: 1 @@ -57,5 +61,6 @@ type: integer unit: pixels mutable: yes + animation: yes minimum: 0 default: 1 diff -Nru mlt-7.4.0/src/modules/kdenlive/filter_freeze.c mlt-7.6.0/src/modules/kdenlive/filter_freeze.c --- mlt-7.4.0/src/modules/kdenlive/filter_freeze.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/kdenlive/filter_freeze.c 2022-04-19 08:45:42.000000000 +0000 @@ -63,10 +63,10 @@ mlt_service_get_frame( mlt_producer_service(producer), &freeze_frame, 0 ); mlt_properties freeze_properties = MLT_FRAME_PROPERTIES( freeze_frame ); - mlt_properties_set( freeze_properties, "rescale.interp", mlt_properties_get( props, "rescale.interp" ) ); + mlt_properties_set( freeze_properties, "consumer.rescale", mlt_properties_get( props, "consumer.rescale" ) ); mlt_properties_set_double( freeze_properties, "aspect_ratio", mlt_frame_get_aspect_ratio( frame ) ); mlt_properties_set_int( freeze_properties, "progressive", mlt_properties_get_int( props, "progressive" ) ); - mlt_properties_set_int( freeze_properties, "consumer_deinterlace", mlt_properties_get_int( props, "consumer_deinterlace" ) || mlt_properties_get_int( properties, "deinterlace" ) ); + mlt_properties_set_int( freeze_properties, "consumer.progressive", mlt_properties_get_int( props, "consumer.progressive" ) || mlt_properties_get_int( properties, "deinterlace" ) ); mlt_properties_set_data( properties, "freeze_frame", freeze_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); mlt_properties_set_position( properties, "_frame", pos ); } diff -Nru mlt-7.4.0/src/modules/kdenlive/filter_wave.c mlt-7.6.0/src/modules/kdenlive/filter_wave.c --- mlt-7.4.0/src/modules/kdenlive/filter_wave.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/kdenlive/filter_wave.c 2022-04-19 08:45:42.000000000 +0000 @@ -2,6 +2,7 @@ * wave.c -- wave filter * Copyright (C) ?-2007 Leny Grisel * Copyright (C) 2007 Jean-Baptiste Mardelle + * Copyright (c) 2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,6 +22,7 @@ #include #include #include +#include #include #include @@ -35,28 +37,45 @@ return src[CLAMP(x+y*w, 0, w*h-1) * 4 + z]; } +typedef struct { + uint8_t *src; + int src_w; + int src_h; + uint8_t *dst; + mlt_position position; + int speed; + int factor; + int deformX; + int deformY; +} slice_desc; + // the main meat of the algorithm lies here -static void DoWave(uint8_t *src, int src_w, int src_h, uint8_t *dst, mlt_position position, int speed, int factor, int deformX, int deformY) +static int do_wave_slice_proc(int id, int index, int jobs, void* data) { + (void) id; // unused + slice_desc* d = (slice_desc*) data; + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, d->src_h, &slice_line_start); + int slice_line_end = slice_line_start + slice_height; register int x, y; int decalY, decalX, z; float amplitude, phase, pulsation; - register int uneven = src_w % 2; - int w = (src_w - uneven ) / 2; - amplitude = factor; - pulsation = 0.5 / factor; // smaller means bigger period - phase = position * pulsation * speed / 10; // smaller means longer - for (y=0;ysrc_w % 2; + int w = (d->src_w - uneven ) / 2; + amplitude = d->factor; + pulsation = 0.5 / d->factor; // smaller means bigger period + phase = d->position * pulsation * d->speed / 10; // smaller means longer + uint8_t* dst = d->dst + (slice_line_start * d->src_w * 2); + for (y=slice_line_start;ydeformX ? sin(pulsation * y + phase) * amplitude : 0; for (x=0;xdeformY ? sin(pulsation * x * 2 + phase) * amplitude : 0; for (z=0; z<4; z++) - *dst++ = getPoint(src, w, src_h, (x+decalX), (y+decalY), z); + *dst++ = getPoint(d->src, w, d->src_h, (x+decalX), (y+decalY), z); } if (uneven) { decalY = sin(pulsation * x * 2 + phase) * amplitude; for (z=0; z<2; z++) - *dst++ = getPoint(src, w, src_h, (x+decalX), (y+decalY), z); + *dst++ = getPoint(d->src, w, d->src_h, (x+decalX), (y+decalY), z); } } } @@ -103,7 +122,17 @@ { int image_size = *width * (*height) * 2; uint8_t *dst = mlt_pool_alloc (image_size); - DoWave(*image, *width, (*height), dst, position, speed, factor, deformX, deformY); + slice_desc desc; + desc.src = *image; + desc.src_w = *width; + desc.src_h = *height; + desc.dst = dst; + desc.position = position; + desc.speed = speed; + desc.factor = factor; + desc.deformX = deformX; + desc.deformY = deformY; + mlt_slices_run_normal(0, do_wave_slice_proc, &desc); *image = dst; mlt_frame_set_image( frame, *image, image_size, mlt_pool_release ); } diff -Nru mlt-7.4.0/src/modules/kdenlive/filter_wave.yml mlt-7.6.0/src/modules/kdenlive/filter_wave.yml --- mlt-7.4.0/src/modules/kdenlive/filter_wave.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/kdenlive/filter_wave.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.2 +schema_version: 7.0 type: filter identifier: wave title: Wave @@ -10,7 +10,7 @@ tags: - Video parameters: - - identifier: start (*deprecated*) + - identifier: start (*DEPRECATED*) title: Amplitude argument: yes type: integer @@ -25,7 +25,7 @@ default: 10 minimum: 1 - - identifier: end (*deprecated*) + - identifier: end (*DEPRECATED*) title: End amplitude type: integer mutable: yes @@ -37,22 +37,26 @@ description: > If this value is set the start and end parameters are ignored. mutable: yes + animation: yes minimum: 1 - identifier: speed title: Speed type: integer mutable: yes + animation: yes default: 5 - identifier: deformX title: Deform horizontally? type: boolean mutable: yes + animation: yes default: 1 - identifier: deformY title: Deform vertically? type: boolean mutable: yes + animation: yes default: 1 diff -Nru mlt-7.4.0/src/modules/kdenlive/producer_framebuffer.c mlt-7.6.0/src/modules/kdenlive/producer_framebuffer.c --- mlt-7.4.0/src/modules/kdenlive/producer_framebuffer.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/kdenlive/producer_framebuffer.c 2022-04-19 08:45:42.000000000 +0000 @@ -158,7 +158,7 @@ uint8_t *first_alpha = mlt_properties_get_data( first_frame_properties, "alpha", NULL ); if ( !first_image ) { - mlt_properties_set( first_frame_properties, "rescale.interp", mlt_properties_get( frame_properties, "rescale.interp" ) ); + mlt_properties_set( first_frame_properties, "consumer.rescale", mlt_properties_get( frame_properties, "consumer.rescale" ) ); int error = mlt_frame_get_image( first_frame, &first_image, format, width, height, writable ); diff -Nru mlt-7.4.0/src/modules/movit/consumer_xgl.c mlt-7.6.0/src/modules/movit/consumer_xgl.c --- mlt-7.4.0/src/modules/movit/consumer_xgl.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/consumer_xgl.c 2022-04-19 08:45:42.000000000 +0000 @@ -565,7 +565,7 @@ // Default scaler mlt_properties_set( this->properties, "rescale", "bilinear" ); - mlt_properties_set( this->properties, "deinterlace_method", "onefield" ); + mlt_properties_set( this->properties, "consumer.deinterlacer", "onefield" ); // default image format mlt_properties_set( this->properties, "mlt_image_format", "glsl" ); diff -Nru mlt-7.4.0/src/modules/movit/consumer_xgl.yml mlt-7.6.0/src/modules/movit/consumer_xgl.yml --- mlt-7.4.0/src/modules/movit/consumer_xgl.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/consumer_xgl.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,14 @@ +schema_version: 7.0 +type: consumer +identifier: xgl +title: OpenGL Video (*DEPRECATED*) +version: 1 +copyright: Christophe Thommeret +license: LGPLv2.1 +language: en +tags: + - Video +description: Display the video only in a X11 window using OpenGL. +notes: > + The window is a fixed size 1280x720 regardless the profile or consumer + width and height properties. diff -Nru mlt-7.4.0/src/modules/movit/factory.c mlt-7.6.0/src/modules/movit/factory.c --- mlt-7.4.0/src/modules/movit/factory.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/factory.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2019 Dan Dennedy + * Copyright (C) 2013-2022 Dan Dennedy * factory.c -- the factory method interfaces * * This program is free software; you can redistribute it and/or modify @@ -56,6 +56,7 @@ { #if !defined(__APPLE__) && !defined(_WIN32) MLT_REGISTER( mlt_service_consumer_type, "xgl", consumer_xgl_init ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "xgl", metadata, "consumer_xgl.yml" ); #endif MLT_REGISTER( mlt_service_filter_type, "glsl.manager", filter_glsl_manager_init ); MLT_REGISTER( mlt_service_filter_type, "movit.blur", filter_movit_blur_init ); @@ -78,7 +79,10 @@ MLT_REGISTER( mlt_service_transition_type, "movit.mix", transition_movit_mix_init ); MLT_REGISTER( mlt_service_transition_type, "movit.overlay", transition_movit_overlay_init ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "glsl.manager", metadata, "filter_glsl_manager.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.blur", metadata, "filter_movit_blur.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.convert", metadata, "filter_movit_convert.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.crop", metadata, "filter_movit_crop.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.diffusion", metadata, "filter_movit_diffusion.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.flip", metadata, "filter_movit_flip.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.glow", metadata, "filter_movit_glow.yml" ); @@ -86,6 +90,8 @@ MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.mirror", metadata, "filter_movit_mirror.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.opacity", metadata, "filter_movit_opacity.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.rect", metadata, "filter_movit_rect.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.resample", metadata, "filter_movit_resample.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.resize", metadata, "filter_movit_resize.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.saturation", metadata, "filter_movit_saturation.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.sharpen", metadata, "filter_movit_deconvolution_sharpen.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.vignette", metadata, "filter_movit_vignette.yml" ); diff -Nru mlt-7.4.0/src/modules/movit/filter_glsl_manager.yml mlt-7.6.0/src/modules/movit/filter_glsl_manager.yml --- mlt-7.4.0/src/modules/movit/filter_glsl_manager.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_glsl_manager.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,15 @@ +schema_version: 7.0 +type: filter +identifier: glsl.manager +title: GLSL Manager +version: 1 +copyright: Dan Dennedy +creator: Steinar H. Gunderson +license: GPLv2 +language: en +description: > + This is a special filter to manage OpenGL and Movit. + See https://mltframework.org/docs/opengl/ for more information. +tags: + - Video + - Hidden diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_blur.yml mlt-7.6.0/src/modules/movit/filter_movit_blur.yml --- mlt-7.4.0/src/modules/movit/filter_movit_blur.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_blur.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: movit.blur title: Blur (GLSL) @@ -21,3 +21,4 @@ minimum: 0 default: 3 mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_convert.cpp mlt-7.6.0/src/modules/movit/filter_movit_convert.cpp --- mlt-7.4.0/src/modules/movit/filter_movit_convert.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_convert.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_movit_convert.cpp - * Copyright (C) 2013-2015 Dan Dennedy + * Copyright (C) 2013-2022 Dan Dennedy * * 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 @@ -113,10 +113,10 @@ // Also, update the frame's color_trc property with the selection. static GammaCurve getGammaCurve( mlt_properties properties ) { - const char *color_trc = mlt_properties_get( properties, "consumer_color_trc" ); + const char *color_trc = mlt_properties_get( properties, "consumer.color_trc" ); if ( color_trc ) { // If specified with enum or int. - int n = mlt_properties_get_int( properties, "consumer_color_trc" ); + int n = mlt_properties_get_int( properties, "consumer.color_trc" ); switch ( n ) { case AVCOL_TRC_BT709: case AVCOL_TRC_SMPTE170M: @@ -185,7 +185,7 @@ if ( mlt_properties_get_int( properties, "force_full_luma" ) ) { ycbcr_format->full_range = true; } else { - ycbcr_format->full_range = ( mlt_properties_get_int( properties, "full_luma" ) == 1 ); + ycbcr_format->full_range = ( mlt_properties_get_int( properties, "full_range" ) == 1 ); } // TODO: make new frame properties set by producers diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_convert.yml mlt-7.6.0/src/modules/movit/filter_movit_convert.yml --- mlt-7.4.0/src/modules/movit/filter_movit_convert.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_convert.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,17 @@ +schema_version: 7.0 +type: filter +identifier: movit.convert +title: Image Converter (GLSL) +version: 1 +copyright: Dan Dennedy +creator: Steinar H. Gunderson +license: GPLv2 +language: en +description: Remove pixels from the edges of the video. +tags: + - Video + - Hidden +description: Converts the colorspace and pixel format. +notes: > + This is not intended to be created directly. Rather, the loader producer + loads it if it is available to set the convert_image function pointer on frames. diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_crop.yml mlt-7.6.0/src/modules/movit/filter_movit_crop.yml --- mlt-7.4.0/src/modules/movit/filter_movit_crop.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_crop.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,17 @@ +schema_version: 7.0 +type: filter +identifier: movit.crop +title: Crop (GLSL) +version: 1 +copyright: Dan Dennedy +creator: Steinar H. Gunderson +license: GPLv2 +language: en +description: Remove pixels from the edges of the video. +tags: + - Video +notes: > + This filter is meant to be included as a normalizing filter attached + automatically by the loader so that cropping occurs early in the processing + stack and can request the full resolution of the source image. Then, the core + crop filter can be use to set the parameters of the crop operation. diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_deconvolution_sharpen.yml mlt-7.6.0/src/modules/movit/filter_movit_deconvolution_sharpen.yml --- mlt-7.4.0/src/modules/movit/filter_movit_deconvolution_sharpen.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_deconvolution_sharpen.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: movit.sharpen title: Deconvolution Sharpen (GLSL) @@ -27,6 +27,7 @@ maximum: 25 default: 5 mutable: yes + animation: yes - identifier: circle_radius title: Circle Radius @@ -34,6 +35,7 @@ minimum: 0 default: 2 mutable: yes + animation: yes - identifier: gaussian_radius title: Gaussian Radius @@ -41,6 +43,7 @@ minimum: 0 default: 0 mutable: yes + animation: yes - identifier: correlation title: Correlation @@ -48,6 +51,7 @@ minimum: 0 default: 0.95 mutable: yes + animation: yes - identifier: noise title: Noise Level @@ -55,3 +59,4 @@ minimum: 0 default: 0.01 mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_diffusion.yml mlt-7.6.0/src/modules/movit/filter_movit_diffusion.yml --- mlt-7.4.0/src/modules/movit/filter_movit_diffusion.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_diffusion.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: movit.diffusion title: Diffusion (GLSL) @@ -27,6 +27,7 @@ minimum: 0.0 default: 3.0 mutable: yes + animation: yes - identifier: mix title: Blurriness @@ -35,3 +36,4 @@ maximum: 1.0 default: 0.3 mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_glow.yml mlt-7.6.0/src/modules/movit/filter_movit_glow.yml --- mlt-7.4.0/src/modules/movit/filter_movit_glow.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_glow.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: movit.glow title: Glow (GLSL) @@ -20,6 +20,7 @@ minimum: 0.0 default: 20.0 mutable: yes + animation: yes - identifier: blur_mix title: Highlight Blurriness @@ -28,6 +29,7 @@ maximum: 1.0 default: 1.0 mutable: yes + animation: yes - identifier: highlight_cutoff title: Highlight Cutoff Threshold @@ -36,3 +38,4 @@ maximum: 1.0 default: 0.2 mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_opacity.yml mlt-7.6.0/src/modules/movit/filter_movit_opacity.yml --- mlt-7.4.0/src/modules/movit/filter_movit_opacity.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_opacity.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: movit.opacity title: Opacity (GLSL) @@ -25,6 +25,7 @@ maximum: 1 default: 1 mutable: yes + animation: yes - identifier: alpha title: Alpha @@ -38,3 +39,4 @@ maximum: 1 default: -1 mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_rect.yml mlt-7.6.0/src/modules/movit/filter_movit_rect.yml --- mlt-7.4.0/src/modules/movit/filter_movit_rect.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_rect.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: movit.rect title: Position and Size (GLSL) @@ -16,9 +16,9 @@ - identifier: rect title: Rectangle type: rect - description: > - Keyframable rectangle specification. + description: Rectangle specifying the position of the top, left corner and size. mutable: yes + animation: yes - identifier: distort title: Ignore aspect ratio diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_resample.cpp mlt-7.6.0/src/modules/movit/filter_movit_resample.cpp --- mlt-7.4.0/src/modules/movit/filter_movit_resample.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_resample.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -60,7 +60,7 @@ // Deinterlace if height is changing to prevent fields mixing on interpolation if ( iheight != oheight ) - mlt_properties_set_int( properties, "consumer_deinterlace", 1 ); + mlt_properties_set_int( properties, "consumer.progressive", 1 ); GlslManager::get_instance()->lock_service( frame ); mlt_properties_set_int( filter_properties, "_movit.parms.int.width", owidth ); diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_resample.yml mlt-7.6.0/src/modules/movit/filter_movit_resample.yml --- mlt-7.4.0/src/modules/movit/filter_movit_resample.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_resample.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,17 @@ +schema_version: 7.0 +type: filter +identifier: movit.resample +title: Image Scaler (GLSL) +version: 1 +copyright: Dan Dennedy +creator: Steinar H. Gunderson +license: GPLv2 +language: en +description: Change the resolution of a video or image. +tags: + - Video + - Hidden +notes: > + This is not intended to be created directly. Rather, the rescale filter + loads it if it is available to normalize video and image inputs to the + consumer/profile resolution. diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_resize.cpp mlt-7.6.0/src/modules/movit/filter_movit_resize.cpp --- mlt-7.4.0/src/modules/movit/filter_movit_resize.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_resize.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -106,7 +106,7 @@ mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio ); // Skip processing if requested. - char *rescale = mlt_properties_get( properties, "rescale.interp" ); + char *rescale = mlt_properties_get( properties, "consumer.rescale" ); if ( *format == mlt_image_none || ( rescale && !strcmp( rescale, "none" ) ) ) return mlt_frame_get_image( frame, image, format, width, height, writable ); diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_resize.yml mlt-7.6.0/src/modules/movit/filter_movit_resize.yml --- mlt-7.4.0/src/modules/movit/filter_movit_resize.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_resize.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,19 @@ +schema_version: 7.0 +type: filter +identifier: movit.resize +title: Image Padding (GLSL) +version: 1 +copyright: Dan Dennedy +creator: Steinar H. Gunderson +license: GPLv2 +language: en +description: Pad an image with black to fulfill the requested image size. +tags: + - Video + - Hidden + +notes: > + Normally resize is used to pad the producer's output to what the consumer has + requested after an upstream filter first scales the image to maximise + usage of the image area. This filter is automatically invoked by the loader + as part of image normalization. diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_saturation.yml mlt-7.6.0/src/modules/movit/filter_movit_saturation.yml --- mlt-7.4.0/src/modules/movit/filter_movit_saturation.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_saturation.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: movit.saturation title: Saturation (GLSL) @@ -23,3 +23,4 @@ minimum: 0 default: 1 mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/movit/filter_movit_vignette.yml mlt-7.6.0/src/modules/movit/filter_movit_vignette.yml --- mlt-7.4.0/src/modules/movit/filter_movit_vignette.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/filter_movit_vignette.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: movit.vignette title: Vignette (GLSL) @@ -21,6 +21,7 @@ maximum: 1.0 default: 0.3 mutable: yes + animation: yes - identifier: inner_radius title: Inner Radius @@ -29,3 +30,4 @@ maximum: 1.0 default: 0.3 mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/movit/transition_movit_mix.yml mlt-7.6.0/src/modules/movit/transition_movit_mix.yml --- mlt-7.4.0/src/modules/movit/transition_movit_mix.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/movit/transition_movit_mix.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: transition identifier: movit.mix title: Dissolve (GLSL) @@ -12,21 +12,15 @@ description: A simple video cross-fade or mixing effect. parameters: - - identifier: argument - title: Mix Level - description: Performs a dissolve if a mix level is not supplied. - type: float - minimum: 0 - maximum: 1 - mutable: yes - - identifier: mix + argument: yes title: Mix Level description: Performs a dissolve if a mix level is not supplied. type: float minimum: 0 maximum: 1 mutable: yes + animation: yes - identifier: reverse title: Reverse diff -Nru mlt-7.4.0/src/modules/ndi/consumer_ndi.c mlt-7.6.0/src/modules/ndi/consumer_ndi.c --- mlt-7.4.0/src/modules/ndi/consumer_ndi.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/ndi/consumer_ndi.c 2022-04-19 08:45:42.000000000 +0000 @@ -360,7 +360,7 @@ parent->is_stopped = consumer_ndi_is_stopped; mlt_properties properties = MLT_CONSUMER_PROPERTIES( parent ); - mlt_properties_set( properties, "deinterlace_method", "onefield" ); + mlt_properties_set( properties, "consumer.deinterlacer", "onefield" ); return parent; diff -Nru mlt-7.4.0/src/modules/ndi/consumer_ndi.yml mlt-7.6.0/src/modules/ndi/consumer_ndi.yml --- mlt-7.4.0/src/modules/ndi/consumer_ndi.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/ndi/consumer_ndi.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: consumer identifier: ndi title: NDI Output @@ -12,9 +12,10 @@ - Network description: Audio/Video over IP output using NewTek's NDI technology parameters: - - identifier: argument + - identifier: resource + argument: yes type: string - title: NDI Source name + title: NDI Sender name description: Name used for discovery by NDI receivers on the network required: yes mutable: no diff -Nru mlt-7.4.0/src/modules/ndi/producer_ndi.yml mlt-7.6.0/src/modules/ndi/producer_ndi.yml --- mlt-7.4.0/src/modules/ndi/producer_ndi.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/ndi/producer_ndi.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: producer identifier: ndi title: NDI Input @@ -12,7 +12,8 @@ - Network description: Audio/Video over IP input using NewTek's NDI technology parameters: - - identifier: argument + - identifier: resource + argument: yes type: string title: NDI Source name description: Name of the NDI Source to receive diff -Nru mlt-7.4.0/src/modules/normalize/filter_volume.yml mlt-7.6.0/src/modules/normalize/filter_volume.yml --- mlt-7.4.0/src/modules/normalize/filter_volume.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/normalize/filter_volume.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: volume title: Volume @@ -13,10 +13,12 @@ Adjust an audio stream's volume level. This filter is based on the 'normalize' utility parameters: - - identifier: argument (*deprecated*) + - identifier: gain (*DEPRECATED*) + argument: yes title: Gain type: string description: > + This parameter is deprecated; use "level" instead. The gain may be indicated as a floating point value of the gain adjustment. @@ -68,7 +70,7 @@ applied during normalisation. default: 20dB mutable: yes - - identifier: end (*deprecated*) + - identifier: end (*DEPRECATED*) title: End gain type: string description: > @@ -93,3 +95,4 @@ Properties "gain" and "end" are ignored if this is set. unit: dB mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/oldfilm/CMakeLists.txt mlt-7.6.0/src/modules/oldfilm/CMakeLists.txt --- mlt-7.4.0/src/modules/oldfilm/CMakeLists.txt 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/CMakeLists.txt 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,5 @@ add_library(mltoldfilm MODULE + common.c factory.c filter_dust.c filter_grain.c diff -Nru mlt-7.4.0/src/modules/oldfilm/common.c mlt-7.6.0/src/modules/oldfilm/common.c --- mlt-7.4.0/src/modules/oldfilm/common.c 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/common.c 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 Meltytech, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "common.h" +#include + + +void oldfilm_init_seed( oldfilm_rand_seed* seed, int init ) +{ + // Use the initial value to initialize the seed to arbitrary values. + // This causes the algorithm to produce consistent results each time for the same frame number. + seed->x = 521288629 + init - ( init << 16 ); + seed->y = 362436069 - init + ( init << 16 ); +} + +int oldfilm_fast_rand( oldfilm_rand_seed* seed ) +{ + static unsigned int a = 18000, b = 30903; + seed->x = a * ( seed->x & 65535 ) + ( seed->x >> 16 ); + seed->y = b * ( seed->y & 65535 ) + ( seed->y >> 16 ); + int r = ( seed->x << 16 ) + ( seed->y & 65535 ); + return abs(r); +} diff -Nru mlt-7.4.0/src/modules/oldfilm/common.h mlt-7.6.0/src/modules/oldfilm/common.h --- mlt-7.4.0/src/modules/oldfilm/common.h 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/common.h 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 Meltytech, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef COMMON_H +#define COMMON_H + +typedef struct +{ + unsigned int x; + unsigned int y; +} oldfilm_rand_seed; + +void oldfilm_init_seed( oldfilm_rand_seed* seed, int init ); +int oldfilm_fast_rand( oldfilm_rand_seed* seed ); + +#endif // COMMON_H diff -Nru mlt-7.4.0/src/modules/oldfilm/filter_dust.c mlt-7.6.0/src/modules/oldfilm/filter_dust.c --- mlt-7.4.0/src/modules/oldfilm/filter_dust.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/filter_dust.c 2022-04-19 08:45:42.000000000 +0000 @@ -134,7 +134,7 @@ luma_width = dx; luma_height = luma_width * mlt_properties_get_int( MLT_FRAME_PROPERTIES ( luma_frame ) , "height" ) / mlt_properties_get_int( MLT_FRAME_PROPERTIES ( luma_frame ) , "width" ); - mlt_properties_set( MLT_FRAME_PROPERTIES( luma_frame ), "rescale.interp", "best" );// none/nearest/tiles/hyper + mlt_properties_set( MLT_FRAME_PROPERTIES( luma_frame ), "consumer.rescale", "best" );// none/nearest/tiles/hyper mlt_frame_get_image( luma_frame, &luma_image, &luma_format, &luma_width, &luma_height, 0 ); alpha = mlt_frame_get_alpha( luma_frame ); diff -Nru mlt-7.4.0/src/modules/oldfilm/filter_dust.yml mlt-7.6.0/src/modules/oldfilm/filter_dust.yml --- mlt-7.4.0/src/modules/oldfilm/filter_dust.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/filter_dust.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter # consumer, filter, producer, or transition identifier: dust title: Dust @@ -28,7 +28,8 @@ minimum: 0 maximum: 100 default: 2 - mutable: no + mutable: yes + animation: yes widget: spinner unit: '%' @@ -41,6 +42,7 @@ minimum: 0 maximum: 400 default: 10 - mutable: no + mutable: yes + animation: yes widget: spinner diff -Nru mlt-7.4.0/src/modules/oldfilm/filter_grain.c mlt-7.6.0/src/modules/oldfilm/filter_grain.c --- mlt-7.4.0/src/modules/oldfilm/filter_grain.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/filter_grain.c 2022-04-19 08:45:42.000000000 +0000 @@ -17,12 +17,47 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "common.h" #include #include +#include #include #include #include +typedef struct { + uint8_t *image; + int width; + int height; + int noise; + double contrast; + double brightness; + mlt_position pos; + int min; + int max_luma; +} slice_desc; + +static int slice_proc(int id, int index, int jobs, void* data) +{ + (void) id; // unused + slice_desc* d = (slice_desc*) data; + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, d->height, &slice_line_start); + uint8_t *p = d->image + slice_line_start * d->width * 2; + + oldfilm_rand_seed seed; + oldfilm_init_seed(&seed, d->pos * jobs + index); + for (int n = 0; n < slice_height * d->width; n++, p += 2) { + if (p[0] > 20) { + int pix = CLAMP(((double) p[0] - 127.0) * d->contrast + 127.0 + d->brightness, 0, 255); + if (d->noise > 0) { + pix -= oldfilm_fast_rand(&seed) % d->noise - d->noise; + } + p[0] = CLAMP(pix , d->min, d->max_luma); + } + } + + return 0; +} static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { @@ -36,31 +71,20 @@ if ( error == 0 && *image ) { - int h = *height; - int w = *width; - - double position = mlt_filter_get_progress( filter, frame ); - srand(position*10000); - int noise = mlt_properties_anim_get_int( properties, "noise", pos, len ); - double contrast = mlt_properties_anim_get_double( properties, "contrast", pos, len ) / 100.0; - double brightness = 127.0 * (mlt_properties_anim_get_double( properties, "brightness", pos, len ) -100.0 ) / 100.0; - - int x = 0,y = 0,pix = 0; - for ( x = 0; x < w; x++ ) - { - for( y = 0; y < h; y++ ) - { - uint8_t* pixel = (*image + (y) * w * 2 + (x) * 2 ); - if (*pixel > 20) - { - pix = MIN ( MAX ( ( (double)*pixel -127.0 ) * contrast + 127.0 + brightness , 0 ) , 255 ) ; - if ( noise > 0 ) pix -= ( rand() % noise - noise ); - - *pixel = MIN ( MAX ( pix , 0 ) , 255 ); - } - } - } + int full_range = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), "full_range"); + slice_desc desc = { + .image = *image, + .width = *width, + .height = *height, + .noise = noise, + .contrast = mlt_properties_anim_get_double( properties, "contrast", pos, len ) / 100.0, + .brightness = 127.0 * (mlt_properties_anim_get_double( properties, "brightness", pos, len ) -100.0 ) / 100.0, + .pos = pos, + .min = full_range? 0 : 16, + .max_luma = full_range? 255 : 235, + }; + mlt_slices_run_normal(0, slice_proc, &desc); } return error; diff -Nru mlt-7.4.0/src/modules/oldfilm/filter_grain.yml mlt-7.6.0/src/modules/oldfilm/filter_grain.yml --- mlt-7.4.0/src/modules/oldfilm/filter_grain.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/filter_grain.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter # consumer, filter, producer, or transition identifier: grain title: Grain @@ -28,7 +28,8 @@ minimum: 0 maximum: 200 default: 40 - mutable: no + mutable: yes + animation: yes widget: spinner unit: '%' @@ -41,7 +42,8 @@ minimum: 0 maximum: 400 default: 160 - mutable: no + mutable: yes + animation: yes widget: spinner - identifier: brightness @@ -53,5 +55,6 @@ minimum: 0 maximum: 400 default: 70 - mutable: no + mutable: yes + animation: yes widget: spinner diff -Nru mlt-7.4.0/src/modules/oldfilm/filter_lines.c mlt-7.6.0/src/modules/oldfilm/filter_lines.c --- mlt-7.4.0/src/modules/oldfilm/filter_lines.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/filter_lines.c 2022-04-19 08:45:42.000000000 +0000 @@ -17,14 +17,64 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "common.h" #include #include #include +#include #include #include #include +typedef struct { + uint8_t *image; + int width; + int height; + int dx; + int ystart; + int yend; + int xmid; + int type; + double maxdarker; + double maxlighter; + int min; + int max_luma; + int max_chroma; +} slice_desc; + +static int slice_proc(int id, int index, int jobs, void* data) +{ + (void) id; // unused + slice_desc* d = (slice_desc*) data; + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, d->height, &slice_line_start); + uint8_t *p = d->image; + + for (int y = MAX(d->ystart, slice_line_start); y < MIN(d->yend, slice_line_start + slice_height); y++) { + for (int x = -(d->dx); x < d->dx && (x + d->xmid) < d->width; x++) { + if (x + d->xmid > 0) { + int i = (y * d->width + x + d->xmid) * 2; + double diff = 1.0 - (double) abs(x) / d->dx; + switch (d->type) + { + case 1: //blackline + p[i] = CLAMP(p[i] - (double) p[i] * diff * d->maxdarker / 100.0, d->min, d->max_luma); + break; + case 2: //whiteline + p[i] = CLAMP(p[i] + (255.0 - (double) p[i]) * diff * d->maxlighter / 100.0, d->min, d->max_luma); + break; + case 3: //greenline + p[i+1] = CLAMP(p[i+1] - (double) p[i+1] * diff * d->maxlighter / 100.0, d->min, d->max_chroma); + break; + } + + } + } + + } + return 0; +} + static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); @@ -37,13 +87,14 @@ if ( error == 0 && *image ) { - int h = *height; - int w = *width; - int line_width = mlt_properties_anim_get_int( properties, "line_width", pos, len ); int num = mlt_properties_anim_get_int( properties, "num", pos, len ); double maxdarker = (double) mlt_properties_anim_get_int( properties, "darker", pos, len ); double maxlighter = (double) mlt_properties_anim_get_int( properties, "lighter", pos, len ); + int full_range = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), "full_range"); + int min = full_range? 0 : 16; + int max_luma = full_range? 255 : 235; + int max_chroma = full_range? 255 : 240; char buf[256]; char typebuf[256]; @@ -57,74 +108,63 @@ return 0; double position = mlt_filter_get_progress( filter, frame ); - srand(position*10000); - + oldfilm_rand_seed seed; + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); while ( num-- ) { - int type = (rand() % 3 ) + 1; - int x1 = (double)w * rand() / RAND_MAX; - int dx = rand() % line_width; - int x = 0, y = 0; - int ystart = rand() % h; - int yend = rand() % h; + oldfilm_init_seed(&seed, position * 10000 + num); + int type = (oldfilm_fast_rand(&seed) % 3) + 1; + int xmid = (double) (*width) * oldfilm_fast_rand(&seed) / RAND_MAX; + int dx = oldfilm_fast_rand(&seed) % line_width; + int ystart = oldfilm_fast_rand(&seed) % (*height); + int yend = oldfilm_fast_rand(&seed) % (*height); sprintf( buf, "line%d", num); sprintf( typebuf, "typeline%d", num); - maxlighter += rand() % 30 -15; - maxdarker += rand() % 30 -15; + maxlighter += oldfilm_fast_rand(&seed) % 30 - 15; + maxdarker += oldfilm_fast_rand(&seed) % 30 - 15; - if ( mlt_properties_get_int(MLT_FILTER_PROPERTIES( filter ),buf ) ==0 ) - { - mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), buf, x1 ); + if (!mlt_properties_get_int(properties, buf)) { + mlt_properties_set_int(properties, buf, xmid); } - if ( mlt_properties_get_int(MLT_FILTER_PROPERTIES( filter ),typebuf)==0 ) - { - mlt_properties_set_int(MLT_FILTER_PROPERTIES( filter ),typebuf,type); + if (!mlt_properties_get_int(properties, typebuf)) { + mlt_properties_set_int(properties, typebuf, type); } - - x1 = mlt_properties_get_int(MLT_FILTER_PROPERTIES( filter ), buf ); - type = mlt_properties_get_int(MLT_FILTER_PROPERTIES( filter ), typebuf ); - if ( position != mlt_properties_get_double(MLT_FILTER_PROPERTIES( filter ), "last_oldfilm_line_pos")) + xmid = mlt_properties_get_int(properties, buf); + type = mlt_properties_get_int(properties, typebuf); + if (position != mlt_properties_get_double(properties, "last_oldfilm_line_pos")) { - x1 += (rand() % 11 - 5); + xmid += (oldfilm_fast_rand(&seed) % 11 - 5); } - if ( yend < ystart) - { - yend=h; + if (yend < ystart) { + yend = *height; } - - for ( x = -dx ; x < dx && dx != 0 ; x++ ) - { - for( y = ystart; y < yend; y++ ) - { - if ( x + x1 < w && x + x1 > 0) - { - uint8_t* pixel = (*image + (y) * w * 2 + ( x + x1) * 2); - double diff = 1.0 - (double) abs(x) / dx; - switch( type ) - { - case 1: //blackline - *pixel -= ((double) * pixel * diff * maxdarker / 100.0); - break; - case 2: //whiteline - *pixel += ((255.0-(double)*pixel) * diff * maxlighter /100.0); - break; - case 3: //greenline - *(pixel+1) -= ((*(pixel+1)) * diff * maxlighter / 100.0); - break; - } - - } - } + if (dx) { + slice_desc desc = { + .image = *image, + .width = *width, + .height = *height, + .dx = dx, + .ystart = ystart, + .yend = yend, + .xmid = xmid, + .type = type, + .maxdarker = maxdarker, + .maxlighter = maxlighter, + .min = min, + .max_luma = max_luma, + .max_chroma = max_chroma + }; + mlt_slices_run_normal(0, slice_proc, &desc); } - mlt_properties_set_int(MLT_FILTER_PROPERTIES( filter ),buf , x1); + mlt_properties_set_int(properties, buf, xmid); } - mlt_properties_set_double(MLT_FILTER_PROPERTIES( filter ),"last_oldfilm_line_pos", position); + mlt_properties_set_double(properties, "last_oldfilm_line_pos", position); mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); } diff -Nru mlt-7.4.0/src/modules/oldfilm/filter_lines.yml mlt-7.6.0/src/modules/oldfilm/filter_lines.yml --- mlt-7.4.0/src/modules/oldfilm/filter_lines.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/filter_lines.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter # consumer, filter, producer, or transition identifier: lines title: Scratchlines @@ -28,7 +28,8 @@ minimum: 0 maximum: 100 default: 2 - mutable: no + mutable: yes + animation: yes widget: spinner unit: pixel @@ -41,7 +42,8 @@ minimum: 0 maximum: 100 default: 5 - mutable: no + mutable: yes + animation: yes widget: spinner unit: lines @@ -54,7 +56,8 @@ minimum: 0 maximum: 100 default: 40 - mutable: no + mutable: yes + animation: yes widget: spinner - identifier: lighter @@ -66,7 +69,8 @@ minimum: 0 maximum: 100 default: 40 - mutable: no + mutable: yes + animation: yes widget: spinner diff -Nru mlt-7.4.0/src/modules/oldfilm/filter_oldfilm.c mlt-7.6.0/src/modules/oldfilm/filter_oldfilm.c --- mlt-7.4.0/src/modules/oldfilm/filter_oldfilm.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/filter_oldfilm.c 2022-04-19 08:45:42.000000000 +0000 @@ -81,7 +81,7 @@ if ( delta ) { mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter)); delta *= mlt_profile_scale_width(profile, *width); - diffpic = rand() % MAX(delta, 1) * 2 - delta; + diffpic = rand() % MAX(delta, 1) * 2 - delta; } int brightdelta = 0; if (( bdu + bdd ) != 0 ) @@ -110,36 +110,28 @@ ydiff = 1; } - while( y != yend ) - { - for ( x = 0; x < w; x++ ) - { - uint8_t* pic = ( *image + y * w * 2 + x * 2 ); - int newy = y + diffpic; - if ( newy > 0 && newy < h ) - { - uint8_t oldval= *( pic + diffpic * w * 2 ); - if ( ((int) oldval + brightdelta + unevendevelop_delta ) > 255 ) - { - *pic=255; - } - else if ( ( (int) oldval + brightdelta + unevendevelop_delta ) <0 ) - { - *pic=0; - } - else - { - *pic = oldval + brightdelta + unevendevelop_delta; - } - *( pic + 1 ) =* ( pic + diffpic * w * 2 + 1 ); + int full_range = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), "full_range"); + int min = full_range? 0 : 16; + int max_luma = full_range? 255 : 235; + for (; y != yend; y += ydiff) { + int newy = y + diffpic; + uint8_t *p = &(*image)[y * w * 2]; + uint8_t *q = &p[diffpic * w * 2]; + for (x = 0; x < w * 2; x += 2) { + if (newy > 0 && newy < h) { + if (((int) q[x] + brightdelta + unevendevelop_delta ) > max_luma) { + p[x] = max_luma; + }else if (((int) q[x] + brightdelta + unevendevelop_delta) < 0) { + p[x] = min; + } else { + p[x] = q[x] + brightdelta + unevendevelop_delta; + } + p[x+1] = q[x+1]; + } else { + p[x] = min; } - else - { - *pic = 0; - } - } - y += ydiff; + } } } diff -Nru mlt-7.4.0/src/modules/oldfilm/filter_oldfilm.yml mlt-7.6.0/src/modules/oldfilm/filter_oldfilm.yml --- mlt-7.4.0/src/modules/oldfilm/filter_oldfilm.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/filter_oldfilm.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter # consumer, filter, producer, or transition identifier: oldfilm title: Oldfilm @@ -28,7 +28,8 @@ minimum: 0 maximum: 400 default: 14 - mutable: no + mutable: yes + animation: yes widget: spinner unit: pixel @@ -41,7 +42,8 @@ minimum: 0 maximum: 100 default: 20 - mutable: no + mutable: yes + animation: yes widget: spinner unit: '%' @@ -54,7 +56,8 @@ minimum: 0 maximum: 100 default: 20 - mutable: no + mutable: yes + animation: yes widget: spinner - identifier: brightnessdelta_down @@ -66,7 +69,8 @@ minimum: 0 maximum: 100 default: 30 - mutable: no + mutable: yes + animation: yes widget: spinner - identifier: brightnessdelta_every @@ -78,7 +82,8 @@ minimum: 0 maximum: 100 default: 70 - mutable: no + mutable: yes + animation: yes widget: spinner unit: '%' @@ -91,7 +96,8 @@ minimum: 0 maximum: 100 default: 60 - mutable: no + mutable: yes + animation: yes widget: spinner - identifier: unevendevelop_down @@ -103,7 +109,8 @@ minimum: 0 maximum: 100 default: 20 - mutable: no + mutable: yes + animation: yes widget: spinner - identifier: unevendevelop_duration @@ -115,6 +122,7 @@ minimum: 0 maximum: 10000 default: 70 - mutable: no + mutable: yes + animation: yes widget: spinner unit: '%' diff -Nru mlt-7.4.0/src/modules/oldfilm/filter_tcolor.c mlt-7.6.0/src/modules/oldfilm/filter_tcolor.c --- mlt-7.4.0/src/modules/oldfilm/filter_tcolor.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/filter_tcolor.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,7 @@ /* * filter_tcolor.c -- tcolor filter * Copyright (c) 2007 Marco Gittler + * Copyright (c) 2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,11 +20,38 @@ #include #include +#include #include #include #include +typedef struct { + uint8_t* image; + int width; + int height; + double over_cr; + double over_cb; +} slice_desc; + +static int do_slice_proc(int id, int index, int jobs, void* data) +{ + (void) id; // unused + slice_desc* desc = (slice_desc*) data; + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, desc->height, &slice_line_start); + int slice_line_end = slice_line_start + slice_height; + int line_size = desc->width * 2; + int x,y; + for ( y = slice_line_start; y < slice_line_end; y++) + { + uint8_t* p = desc->image + y * line_size; + for ( x = 0; x < line_size; x += 4) + { + p[x+1] = CLAMP( ((double)p[x+1] - 127.0) * desc->over_cb + 127.0, 0, 255); + p[x+3] = CLAMP( ((double)p[x+3] - 127.0) * desc->over_cr + 127.0, 0, 255); + } + } +} static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { @@ -37,24 +65,13 @@ if ( error == 0 && *image ) { - double over_cr = mlt_properties_anim_get_double( properties, "oversaturate_cr", pos, len )/100.0; - double over_cb = mlt_properties_anim_get_double( properties, "oversaturate_cb", pos, len )/100.0; - - int video_width = *width; - int video_height = *height; - - int x,y; - - for ( y = 0; y < video_height; y++) - { - for ( x = 0; x < video_width; x += 2) - { - uint8_t *pix = (*image + y * video_width * 2 + x * 2 + 1); - uint8_t *pix1 = (*image + y * video_width * 2 + x * 2 + 3); - *pix = MIN(MAX( ((double) * pix - 127.0) * over_cb + 127.0,0), 255); - *pix1 = MIN(MAX( ((double) * pix1 - 127.0) * over_cr + 127.0,0), 255); - } - } + slice_desc desc; + desc.over_cr = mlt_properties_anim_get_double( properties, "oversaturate_cr", pos, len )/100.0; + desc.over_cb = mlt_properties_anim_get_double( properties, "oversaturate_cb", pos, len )/100.0; + desc.image = *image; + desc.width = *width; + desc.height = *height; + mlt_slices_run_normal(0, do_slice_proc, &desc); } return error; diff -Nru mlt-7.4.0/src/modules/oldfilm/filter_tcolor.yml mlt-7.6.0/src/modules/oldfilm/filter_tcolor.yml --- mlt-7.4.0/src/modules/oldfilm/filter_tcolor.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/filter_tcolor.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter # consumer, filter, producer, or transition identifier: tcolor title: Technicolor @@ -28,7 +28,8 @@ minimum: -400 maximum: 400 default: 190 - mutable: no + mutable: yes + animation: yes widget: spinner - identifier: oversaturate_cb @@ -40,5 +41,6 @@ minimum: -400 maximum: 400 default: 190 - mutable: no + mutable: yes + animation: yes widget: spinner diff -Nru mlt-7.4.0/src/modules/oldfilm/filter_vignette.c mlt-7.6.0/src/modules/oldfilm/filter_vignette.c --- mlt-7.4.0/src/modules/oldfilm/filter_vignette.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/filter_vignette.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,7 @@ /* * filter_vignette.c -- vignette filter * Copyright (c) 2007 Marco Gittler + * Copyright (c) 2009-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,13 +21,56 @@ #include #include #include +#include #include #include #include -#define SIGMOD_STEPS 1000 -#define POSITION_VALUE(p,s,e) (s+((double)(e-s)*p )) +typedef struct { + uint8_t *image; + int width; + int height; + double smooth; + double radius; + double cx, cy; + double opacity; + int mode; +} slice_desc; + +static int slice_proc(int id, int index, int jobs, void* data) +{ + (void) id; // unused + slice_desc* d = (slice_desc*) data; + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, d->height, &slice_line_start); + uint8_t *p = d->image + slice_line_start * d->width * 2; + int w2 = d->cx, h2 = d->cy; + double delta = 1.0; + + for (int y = slice_line_start; y < slice_line_start + slice_height; y++) { + int h2_pow2 = pow(y - h2, 2.0); + for (int x = 0; x < d->width; x++, p += 2) { + int dx = sqrt(h2_pow2 + pow(x - w2, 2.0)); + if (d->radius - d->smooth > dx) { // center, make not darker + continue; + } else if (d->radius + d->smooth <= dx) { // max dark after smooth area + delta = 0.0; + } else { + // linear pos from of opacity (from 0 to 1) + delta = (d->radius + d->smooth - dx) / (2.0 * d->smooth); + if (d->mode == 1) { + // make cos for smoother non linear fade + delta = pow(cos(((1.0 - delta) * M_PI / 2.0)), 3.0); + } + } + delta = MAX(d->opacity, delta); + p[0] = p[0] * delta; + p[1] = (p[1] - 127.0) * delta + 127.0; + } + } + + return 0; +} static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { @@ -36,58 +80,23 @@ if ( error == 0 && *image ) { - float smooth, radius, cx, cy, opac; mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter ) ; mlt_position pos = mlt_filter_get_position( filter, frame ); mlt_position len = mlt_filter_get_length2( filter, frame ); mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter)); double scale = mlt_profile_scale_width(profile, *width); - - smooth = mlt_properties_anim_get_double( filter_props, "smooth", pos, len ) * 100.0 * scale; - radius = mlt_properties_anim_get_double( filter_props, "radius", pos, len ) * *width; - cx = mlt_properties_anim_get_double( filter_props, "x", pos, len ) * *width; - cy = mlt_properties_anim_get_double( filter_props, "y", pos, len ) * *height; - opac = mlt_properties_anim_get_double( filter_props, "opacity", pos, len ); - int mode = mlt_properties_get_int( filter_props , "mode" ); - - int video_width = *width; - int video_height = *height; - - int x, y; - int w2 = cx, h2 = cy; - double delta = 1.0; - double max_opac = opac; - for ( y=0; y < video_height; y++ ) - { - int h2_pow2 = pow( y - h2, 2.0 ); - for ( x = 0; x < video_width; x++ ) - { - uint8_t *pix = ( *image + y * video_width * 2 + x * 2 ); - int dx = sqrt( h2_pow2 + pow( x - w2, 2.0 )); - - if (radius-smooth > dx) //center, make not darker - { - continue; - } - else if ( radius + smooth <= dx ) //max dark after smooth area - { - delta = 0.0; - } - else - { - // linear pos from of opacity (from 0 to 1) - delta = (double) ( radius + smooth - dx ) / ( 2.0 * smooth ); - if ( mode == 1 ) - { - //make cos for smoother non linear fade - delta = (double) pow( cos((( 1.0 - delta ) * 3.14159 / 2.0 )), 3.0 ); - } - } - delta = MAX( max_opac, delta ); - *pix = (double) (*pix) * delta; - *(pix+1) = ((double)(*(pix+1) - 127.0 ) * delta ) + 127.0; - } - } + slice_desc desc = { + .image = *image, + .width = *width, + .height = *height, + .smooth = mlt_properties_anim_get_double(filter_props, "smooth", pos, len) * 100.0 * scale, + .radius = mlt_properties_anim_get_double( filter_props, "radius", pos, len) * *width, + .cx = mlt_properties_anim_get_double(filter_props, "x", pos, len) * *width, + .cy = mlt_properties_anim_get_double(filter_props, "y", pos, len) * *height, + .opacity = mlt_properties_anim_get_double(filter_props, "opacity", pos, len), + .mode = mlt_properties_get_int(filter_props , "mode") + }; + mlt_slices_run_normal(0, slice_proc, &desc); } return error; diff -Nru mlt-7.4.0/src/modules/oldfilm/filter_vignette.yml mlt-7.6.0/src/modules/oldfilm/filter_vignette.yml --- mlt-7.4.0/src/modules/oldfilm/filter_vignette.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/oldfilm/filter_vignette.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter # consumer, filter, producer, or transition identifier: vignette title: Vignette Effect @@ -26,7 +26,8 @@ type: float readonly: no required: yes - mutable: no + mutable: yes + animation: yes minimum: 0.0 maximum: 1.0 default: 0.8 @@ -36,7 +37,8 @@ type: float readonly: no required: yes - mutable: no + mutable: yes + animation: yes minimum: 0.0 maximum: 1.0 default: 0.5 @@ -46,7 +48,8 @@ type: float readonly: no required: yes - mutable: no + mutable: yes + animation: yes minimum: 0.0 maximum: 1.0 default: 0.5 @@ -56,7 +59,8 @@ type: float readonly: no required: yes - mutable: no + mutable: yes + animation: yes minimum: 0.0 maximum: 1.0 default: 0.5 @@ -66,7 +70,8 @@ type: float readonly: no required: yes - mutable: no + mutable: yes + animation: yes minimum: 0.0 maximum: 1.0 default: 0.0 @@ -77,7 +82,7 @@ description: Use linear (0) or cosinus (1) mode to fade from opac to black readonly: no required: yes - mutable: no + mutable: yes minimum: 0 maximum: 1 default: 0 diff -Nru mlt-7.4.0/src/modules/opencv/filter_opencv_tracker.yml mlt-7.6.0/src/modules/opencv/filter_opencv_tracker.yml --- mlt-7.4.0/src/modules/opencv/filter_opencv_tracker.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/opencv/filter_opencv_tracker.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: opencv.tracker title: OpenCV Motion Tracker @@ -30,7 +30,7 @@ The rectangle defining the object to be followed (from the 1st frame of the filter). required: no readonly: no - mutable: no + mutable: yes default: 0 0 50 50 - identifier: shape @@ -44,7 +44,7 @@ minimum: 0 maximum: 5 default: 0 - mutable: no + mutable: yes - identifier: shape_width title: Shape Width @@ -57,7 +57,7 @@ minimum: -1 maximum: 100 default: 1 - mutable: no + mutable: yes - identifier: shape_color title: Shape Color @@ -80,7 +80,7 @@ minimum: 0 maximum: 100 default: 0 - mutable: no + mutable: yes - identifier: blur_type title: Blur Type @@ -93,7 +93,7 @@ minimum: 0 maximum: 100 default: 0 - mutable: no + mutable: yes - identifier: algo title: Tracker Algorithm @@ -104,14 +104,14 @@ readonly: no required: no default: KCF - mutable: no + mutable: yes - identifier: steps title: Keyframes spacing type: integer description: > Defines the frequency of stored keyframes. A keyframe is created every steps frames. - mutable: yes + mutable: no readonly: no required: no default: 5 @@ -131,6 +131,7 @@ type: string description: > Set after analysis. This is an animated rect following object designated with initial rect property. - mutable: no + mutable: yes + animation: yes readonly: yes diff -Nru mlt-7.4.0/src/modules/plus/CMakeLists.txt mlt-7.6.0/src/modules/plus/CMakeLists.txt --- mlt-7.4.0/src/modules/plus/CMakeLists.txt 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/CMakeLists.txt 2022-04-19 08:45:42.000000000 +0000 @@ -12,7 +12,6 @@ filter_loudness.c filter_loudness_meter.c filter_lumakey.c - filter_pillar_echo.c filter_rgblut.c filter_sepia.c filter_shape.c @@ -63,7 +62,6 @@ filter_loudness_meter.yml filter_loudness.yml filter_lumakey.yml - filter_pillar_echo.yml filter_rgblut.yml filter_sepia.yml filter_shape.yml diff -Nru mlt-7.4.0/src/modules/plus/consumer_blipflash.yml mlt-7.6.0/src/modules/plus/consumer_blipflash.yml --- mlt-7.4.0/src/modules/plus/consumer_blipflash.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/consumer_blipflash.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: consumer identifier: blipflash title: Blip Flash @@ -13,7 +13,8 @@ Calculate the A/V sync for a blip flash source. Sync can be recalculated whenever a blip or a flash is detected. parameters: - - identifier: argument + - identifier: resource + argument: yes title: Report File type: string description: > diff -Nru mlt-7.4.0/src/modules/plus/factory.c mlt-7.6.0/src/modules/plus/factory.c --- mlt-7.4.0/src/modules/plus/factory.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/factory.c 2022-04-19 08:45:42.000000000 +0000 @@ -33,7 +33,6 @@ extern mlt_filter filter_loudness_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_loudness_meter_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_lumakey_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -extern mlt_filter filter_pillar_echo_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_rgblut_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_sepia_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_shape_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); @@ -73,7 +72,6 @@ MLT_REGISTER( mlt_service_filter_type, "loudness", filter_loudness_init ); MLT_REGISTER( mlt_service_filter_type, "loudness_meter", filter_loudness_meter_init ); MLT_REGISTER( mlt_service_filter_type, "lumakey", filter_lumakey_init ); - MLT_REGISTER( mlt_service_filter_type, "pillar_echo", filter_pillar_echo_init ); MLT_REGISTER( mlt_service_filter_type, "rgblut", filter_rgblut_init ); MLT_REGISTER( mlt_service_filter_type, "sepia", filter_sepia_init ); MLT_REGISTER( mlt_service_filter_type, "shape", filter_shape_init ); @@ -103,7 +101,6 @@ MLT_REGISTER_METADATA( mlt_service_filter_type, "loudness", metadata, "filter_loudness.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "loudness_meter", metadata, "filter_loudness_meter.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "lumakey", metadata, "filter_lumakey.yml" ); - MLT_REGISTER_METADATA( mlt_service_filter_type, "pillar_echo", metadata, "filter_pillar_echo.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "rgblut", metadata, "filter_rgblut.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "sepia", metadata, "filter_sepia.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "shape", metadata, "filter_shape.yml" ); diff -Nru mlt-7.4.0/src/modules/plus/filter_affine.c mlt-7.6.0/src/modules/plus/filter_affine.c --- mlt-7.4.0/src/modules/plus/filter_affine.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_affine.c 2022-04-19 08:45:42.000000000 +0000 @@ -84,7 +84,7 @@ mlt_frame_set_position( a_frame, in + position ); // Set the rescale interpolation to match the frame - mlt_properties_set( MLT_FRAME_PROPERTIES( a_frame ), "rescale.interp", mlt_properties_get( frame_properties, "rescale.interp" ) ); + mlt_properties_set( MLT_FRAME_PROPERTIES( a_frame ), "consumer.rescale", mlt_properties_get( frame_properties, "consumer.rescale" ) ); // Special case - aspect_ratio = 0 if ( mlt_frame_get_aspect_ratio( frame ) == 0 ) diff -Nru mlt-7.4.0/src/modules/plus/filter_charcoal.c mlt-7.6.0/src/modules/plus/filter_charcoal.c --- mlt-7.4.0/src/modules/plus/filter_charcoal.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_charcoal.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_charcoal.c -- charcoal filter - * Copyright (C) 2003-2020 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,16 +20,17 @@ #include #include #include +#include #include #include #include -static inline int get_Y( uint8_t *pixels, int width, int height, int x, int y ) +static inline int get_Y( uint8_t *pixels, int width, int height, int x, int y, int max_luma ) { if ( x < 0 || x >= width || y < 0 || y >= height ) { - return 235; + return max_luma; } else { @@ -63,8 +64,64 @@ return p; } -/** Do it :-). -*/ +typedef struct { + uint8_t *image; + uint8_t *dest; + int width; + int height; + int x_scatter; + int y_scatter; + int min; + int max_luma; + int max_chroma; + int invert; + int invert_luma; + float scale; + float mix; +} slice_desc; + +static int slice_proc(int id, int index, int jobs, void* data) +{ + (void) id; // unused + slice_desc* d = (slice_desc*) data; + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, d->height, &slice_line_start); + uint8_t *p = d->dest + slice_line_start * d->width * 2; + uint8_t *q = d->image + slice_line_start * d->width * 2; + int matrix[3][3]; + int sum1; + int sum2; + float sum; + int val; + + for (int y = slice_line_start; y < slice_line_start + slice_height; y++) { + for (int x = 0; x < d->width; x++) { + // Populate the matrix + matrix[0][0] = get_Y(d->image, d->width, d->height, x - d->x_scatter, y - d->y_scatter, d->max_luma); + matrix[0][1] = get_Y(d->image, d->width, d->height, x , y - d->y_scatter, d->max_luma); + matrix[0][2] = get_Y(d->image, d->width, d->height, x + d->x_scatter, y - d->y_scatter, d->max_luma); + matrix[1][0] = get_Y(d->image, d->width, d->height, x - d->x_scatter, y , d->max_luma); + matrix[1][2] = get_Y(d->image, d->width, d->height, x + d->x_scatter, y , d->max_luma); + matrix[2][0] = get_Y(d->image, d->width, d->height, x - d->x_scatter, y + d->y_scatter, d->max_luma); + matrix[2][1] = get_Y(d->image, d->width, d->height, x , y + d->y_scatter, d->max_luma); + matrix[2][2] = get_Y(d->image, d->width, d->height, x + d->x_scatter, y + d->y_scatter, d->max_luma); + + // Do calculations + sum1 = (matrix[2][0] - matrix[0][0]) + ((matrix[2][1] - matrix[0][1]) << 1 ) + (matrix[2][2] - matrix[2][0]); + sum2 = (matrix[0][2] - matrix[0][0]) + ((matrix[1][2] - matrix[1][0]) << 1 ) + (matrix[2][2] - matrix[2][0]); + sum = d->scale * sqrti(sum1 * sum1 + sum2 * sum2); + + // Assign value + *p++ = !d->invert ? (sum >= d->min && sum <= d->max_luma ? d->invert_luma - sum : sum < d->min ? d->max_luma : d->min) : + (sum >= d->min && sum <= d->max_luma ? sum : sum < d->min ? d->min : d->max_luma); + q++; + val = 128 + d->mix * (*q++ - 128); + val = CLAMP(val, d->min, d->max_chroma); + *p++ = val; + } + } + + return 0; +} static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { @@ -76,17 +133,15 @@ // Get the image *format = mlt_image_yuv422; - int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); + int error = mlt_frame_get_image(frame, image, format, width, height, 0); // Only process if we have no error and a valid colour space - if ( error == 0 ) - { + if ( error == 0 ) { + int size = *width * *height * 2; + int full_range = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), "full_range"); // Get the charcoal scatter value int x_scatter = mlt_properties_anim_get_double( properties, "x_scatter", position, length ); int y_scatter = mlt_properties_anim_get_double( properties, "y_scatter", position, length ); - float scale = mlt_properties_anim_get_double( properties, "scale" ,position, length); - float mix = mlt_properties_anim_get_double( properties, "mix", position, length); - int invert = mlt_properties_anim_get_int( properties, "invert", position, length); mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter)); double scale_x = mlt_profile_scale_width(profile, *width); double scale_y = mlt_profile_scale_height(profile, *height); @@ -95,60 +150,29 @@ y_scatter = MAX(1, lrint(y_scatter * scale_y)); } - // We'll process pixel by pixel - int x = 0; - int y = 0; - - // We need to create a new frame as this effect modifies the input - uint8_t *temp = mlt_pool_alloc( *width * *height * 2 ); - uint8_t *p = temp; - uint8_t *q = *image; - - // Calculations are carried out on a 3x3 matrix - int matrix[ 3 ][ 3 ]; - - // Used to carry out the matrix calculations - int sum1; - int sum2; - float sum; - int val; - - // Loop for each row - for ( y = 0; y < *height; y ++ ) - { - // Loop for each pixel - for ( x = 0; x < *width; x ++ ) - { - // Populate the matrix - matrix[ 0 ][ 0 ] = get_Y( *image, *width, *height, x - x_scatter, y - y_scatter ); - matrix[ 0 ][ 1 ] = get_Y( *image, *width, *height, x , y - y_scatter ); - matrix[ 0 ][ 2 ] = get_Y( *image, *width, *height, x + x_scatter, y - y_scatter ); - matrix[ 1 ][ 0 ] = get_Y( *image, *width, *height, x - x_scatter, y ); - matrix[ 1 ][ 2 ] = get_Y( *image, *width, *height, x + x_scatter, y ); - matrix[ 2 ][ 0 ] = get_Y( *image, *width, *height, x - x_scatter, y + y_scatter ); - matrix[ 2 ][ 1 ] = get_Y( *image, *width, *height, x , y + y_scatter ); - matrix[ 2 ][ 2 ] = get_Y( *image, *width, *height, x + x_scatter, y + y_scatter ); - - // Do calculations - sum1 = (matrix[2][0] - matrix[0][0]) + ( (matrix[2][1] - matrix[0][1]) << 1 ) + (matrix[2][2] - matrix[2][0]); - sum2 = (matrix[0][2] - matrix[0][0]) + ( (matrix[1][2] - matrix[1][0]) << 1 ) + (matrix[2][2] - matrix[2][0]); - sum = scale * sqrti( sum1 * sum1 + sum2 * sum2 ); - - // Assign value - *p ++ = !invert ? ( sum >= 16 && sum <= 235 ? 251 - sum : sum < 16 ? 235 : 16 ) : - ( sum >= 16 && sum <= 235 ? sum : sum < 16 ? 16 : 235 ); - q ++; - val = 128 + mix * ( *q ++ - 128 ); - val = val < 16 ? 16 : val > 240 ? 240 : val; - *p ++ = val; - } - } + slice_desc desc = { + // We need to create a new frame as this effect modifies the input + .image = *image, + .dest = mlt_pool_alloc(size), + .width = *width, + .height = *height, + .x_scatter = x_scatter, + .y_scatter = y_scatter, + .min = full_range? 0 : 16, + .max_luma = full_range? 255 : 235, + .max_chroma = full_range? 255 : 240, + .invert = mlt_properties_anim_get_int(properties, "invert", position, length), + .invert_luma = full_range? 255 : 251, + .scale = mlt_properties_anim_get_double(properties, "scale", position, length), + .mix = mlt_properties_anim_get_double(properties, "mix", position, length) + }; + mlt_slices_run_normal(0, slice_proc, &desc); // Return the created image - *image = temp; + *image = desc.dest; // Store new and destroy old - mlt_frame_set_image( frame, *image, *width * *height * 2, mlt_pool_release ); + mlt_frame_set_image(frame, *image, size, mlt_pool_release); } return error; diff -Nru mlt-7.4.0/src/modules/plus/filter_charcoal.yml mlt-7.6.0/src/modules/plus/filter_charcoal.yml --- mlt-7.4.0/src/modules/plus/filter_charcoal.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_charcoal.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: charcoal title: Charcoal @@ -17,6 +17,7 @@ default: 1 minimum: 1 mutable: yes + animation: yes unit: pixels - identifier: y_scatter @@ -25,6 +26,7 @@ default: 1 minimum: 1 mutable: yes + animation: yes unit: pixels - identifier: scale @@ -32,15 +34,18 @@ type: float default: 1.5 mutable: yes + animation: yes - identifier: mix title: Color type: float default: 0 mutable: yes + animation: yes - identifier: invert title: Invert type: boolean default: 0 mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/plus/filter_chroma.c mlt-7.6.0/src/modules/plus/filter_chroma.c --- mlt-7.4.0/src/modules/plus/filter_chroma.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_chroma.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,7 +1,6 @@ /* * filter_chroma.c -- Maps a chroma key to the alpha channel - * Copyright (C) 2005 Visual Media Fx Inc. - * Copyright (C) 2021 Meltytech, LLC + * Copyright (C) 2007-2022 Meltytech, LLC * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify @@ -47,13 +46,10 @@ { mlt_filter this = mlt_frame_pop_service( frame ); int variance = 200 * mlt_properties_get_double( MLT_FILTER_PROPERTIES( this ), "variance" ); - int32_t key_val = mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "key" ); - uint8_t r = ( key_val >> 24 ) & 0xff; - uint8_t g = ( key_val >> 16 ) & 0xff; - uint8_t b = ( key_val >> 8 ) & 0xff; + mlt_color key_val = mlt_properties_get_color( MLT_FILTER_PROPERTIES( this ), "key" ); uint8_t u, v; - RGB2UV_601_SCALED( r, g, b, u, v ); + RGB2UV_601_SCALED( key_val.r, key_val.g, key_val.b, u, v ); *format = mlt_image_yuv422; if ( mlt_frame_get_image( frame, image, format, width, height, writable ) == 0 ) @@ -99,7 +95,7 @@ mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { - mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "key", arg == NULL ? "0x0000ff00" : arg ); + mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "key", arg == NULL ? "#0000ff" : arg ); mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "variance", 0.15 ); this->process = filter_process; } diff -Nru mlt-7.4.0/src/modules/plus/filter_chroma_hold.c mlt-7.6.0/src/modules/plus/filter_chroma_hold.c --- mlt-7.4.0/src/modules/plus/filter_chroma_hold.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_chroma_hold.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,7 +1,6 @@ /* * filter_chroma.c -- Maps a chroma key to the alpha channel - * Copyright (C) 2005 Visual Media Fx Inc. - * Author: Charles Yates + * Copyright (C) 2008-2022 Meltytech, LLC * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -44,10 +43,10 @@ { mlt_filter this = mlt_frame_pop_service( frame ); int variance = 200 * mlt_properties_get_double( MLT_FILTER_PROPERTIES( this ), "variance" ); - int32_t key_val = mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "key" ); - uint8_t r = ( key_val >> 24 ) & 0xff; - uint8_t g = ( key_val >> 16 ) & 0xff; - uint8_t b = ( key_val >> 8 ) & 0xff; + mlt_color key_val = mlt_properties_get_color( MLT_FILTER_PROPERTIES( this ), "key" ); + uint8_t r = key_val.r; + uint8_t g = key_val.g; + uint8_t b = key_val.b; uint8_t u, v; RGB2UV_601_SCALED( r, g, b, u, v ); @@ -91,7 +90,7 @@ mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { - mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "key", arg == NULL ? "0xc0000000" : arg ); + mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "key", arg == NULL ? "#c00000" : arg ); mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "variance", 0.15 ); this->process = filter_process; } diff -Nru mlt-7.4.0/src/modules/plus/filter_chroma_hold.yml mlt-7.6.0/src/modules/plus/filter_chroma_hold.yml --- mlt-7.4.0/src/modules/plus/filter_chroma_hold.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_chroma_hold.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,11 +1,28 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: chroma_hold title: Chroma Hold version: 1 -copyright: Visual Media FX ? creator: Charles Yates license: LGPLv2.1 language: en tags: - Video + +parameters: + - identifier: key + argument: yes + type: color + title: Key Color + description: The color to keep. All others are desaturated. + default: #c00000 + mutable: yes + + - identifier: variance + title: Variance + description: The threshold for colors similar to the key color. + type: float + default: 0.15 + minimum: 0 + maximum: 1.0 + mutable: yes diff -Nru mlt-7.4.0/src/modules/plus/filter_chroma.yml mlt-7.6.0/src/modules/plus/filter_chroma.yml --- mlt-7.4.0/src/modules/plus/filter_chroma.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_chroma.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,11 +1,26 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: chroma title: Chroma Key version: 1 -copyright: Visual Media FX ? creator: Charles Yates license: LGPLv2.1 language: en tags: - Video + +parameters: + - identifier: key + title: Key Color + type: color + argument: yes + mutable: yes + default: #0000ff + + - identifier: variance + title: Variance + type: float + mutable: yes + default: 0.15 + minimum: 0 + maximum: 1.0 diff -Nru mlt-7.4.0/src/modules/plus/filter_dynamictext.yml mlt-7.6.0/src/modules/plus/filter_dynamictext.yml --- mlt-7.4.0/src/modules/plus/filter_dynamictext.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_dynamictext.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: dynamictext title: Dynamic text @@ -15,6 +15,7 @@ parameters: - identifier: argument + argument: yes title: Dynamic text type: string description: | diff -Nru mlt-7.4.0/src/modules/plus/filter_invert.c mlt-7.6.0/src/modules/plus/filter_invert.c --- mlt-7.4.0/src/modules/plus/filter_invert.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_invert.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_invert.c -- invert filter - * Copyright (C) 2003-2014 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,42 +19,61 @@ #include #include +#include #include #include #include #include -static inline int clamp( int v, int l, int u ) +typedef struct { + uint8_t* image; + int height; + int width; + int full_range; +} slice_desc; + +static int do_slice_proc(int id, int index, int jobs, void* data) { - return v < l ? l : ( v > u ? u : v ); + (void) id; // unused + slice_desc* desc = (slice_desc*) data; + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, desc->height, &slice_line_start); + int slice_line_end = slice_line_start + slice_height; + int line_size = desc->width * 2; + int min = desc->full_range ? 0 : 16; + int max_luma = desc->full_range ? 255 : 235; + int max_chroma = desc->full_range ? 255 : 240; + int invert_luma = desc->full_range ? 255 : 251; + int x,y; + for ( y = slice_line_start; y < slice_line_end; y++) + { + uint8_t* p = desc->image + y * line_size; + for ( x = 0; x < line_size; x += 2) + { + p[x] = CLAMP(invert_luma - p[x], min, max_luma); + p[x+1] = CLAMP(256 - p[x+1], min, max_chroma); + } + } } -/** Do it :-). -*/ - static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the image mlt_filter filter = mlt_frame_pop_service( frame ); - int mask = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "alpha" ); *format = mlt_image_yuv422; int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); - - // Only process if we have no error and a valid colour space - if ( error == 0 ) + // Only process if we have no error and a valid color space + if ( error == 0 && *format == mlt_image_yuv422) { - uint8_t *p = *image; - uint8_t *q = *image + *width * *height * 2; - uint8_t *r = *image; - - while ( p != q ) - { - *p ++ = clamp( 251 - *r ++, 16, 235 ); - *p ++ = clamp( 256 - *r ++, 16, 240 ); - } + slice_desc desc; + desc.image = *image; + desc.width = *width; + desc.height = *height; + desc.full_range = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), "full_range"); + mlt_slices_run_normal(0, do_slice_proc, &desc); + int mask = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "alpha" ); if ( mask ) { int size = *width * *height; diff -Nru mlt-7.4.0/src/modules/plus/filter_invert.yml mlt-7.6.0/src/modules/plus/filter_invert.yml --- mlt-7.4.0/src/modules/plus/filter_invert.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_invert.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: invert title: Invert @@ -9,3 +9,12 @@ language: en tags: - Video + +parameters: + - identifier: alpha + type: integer + title: Alpha Channel + description: A value to overwrite the alpha channel. + minimum: 1 + maximum: 255 + mutable: yes diff -Nru mlt-7.4.0/src/modules/plus/filter_lift_gamma_gain.c mlt-7.6.0/src/modules/plus/filter_lift_gamma_gain.c --- mlt-7.4.0/src/modules/plus/filter_lift_gamma_gain.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_lift_gamma_gain.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_lift_gamma_gain.cpp - * Copyright (C) 2014 Meltytech, LLC + * Copyright (C) 2014-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -32,6 +32,18 @@ double rgain, ggain, bgain; } private_data; +typedef struct +{ + mlt_filter filter; + uint8_t *image; + mlt_image_format format; + int width; + int height; + uint8_t rlut[256]; + uint8_t glut[256]; + uint8_t blut[256]; +} sliced_desc; + static void refresh_lut( mlt_filter filter, mlt_frame frame ) { private_data* self = (private_data*)filter->child; @@ -107,54 +119,68 @@ } } -static void apply_lut( mlt_filter filter, uint8_t* image, mlt_image_format format, int width, int height ) +static int sliced_proc(int id, int index, int jobs, void* data) { - private_data* self = (private_data*)filter->child; - uint8_t* rlut = malloc( sizeof(self->rlut) ); - uint8_t* glut = malloc( sizeof(self->glut) ); - uint8_t* blut = malloc( sizeof(self->blut) ); - int total = width * height + 1; - uint8_t* sample = image; - - // Copy the LUT so that we can be frame-thread safe. - mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); - memcpy( rlut, self->rlut, sizeof(self->rlut) ); - memcpy( glut, self->glut, sizeof(self->glut) ); - memcpy( blut, self->blut, sizeof(self->blut) ); - mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); + (void) id; // unused + sliced_desc* desc = ((sliced_desc*) data); + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, desc->height, &slice_line_start); + int total = desc->width * slice_height + 1; + uint8_t* sample = desc->image + slice_line_start * mlt_image_format_size(desc->format, desc->width, 1, NULL); - switch( format ) + switch( desc->format ) { case mlt_image_rgb: while( --total ) { - *sample = rlut[ *sample ]; + *sample = desc->rlut[ *sample ]; sample++; - *sample = glut[ *sample ]; + *sample = desc->glut[ *sample ]; sample++; - *sample = blut[ *sample ]; + *sample = desc->blut[ *sample ]; sample++; } break; case mlt_image_rgba: while( --total ) { - *sample = rlut[ *sample ]; + *sample = desc->rlut[ *sample ]; sample++; - *sample = glut[ *sample ]; + *sample = desc->glut[ *sample ]; sample++; - *sample = blut[ *sample ]; + *sample = desc->blut[ *sample ]; sample++; sample++; // Skip alpha } break; default: - mlt_log_error( MLT_FILTER_SERVICE( filter ), "Invalid image format: %s\n", mlt_image_format_name( format ) ); + mlt_log_error( MLT_FILTER_SERVICE( desc->filter ), "Invalid image format: %s\n", mlt_image_format_name( desc->format ) ); break; } - free( rlut ); - free( glut ); - free( blut ); + + return 0; +} + +static void apply_lut( mlt_filter filter, uint8_t* image, mlt_image_format format, int width, int height ) +{ + private_data* self = (private_data*)filter->child; + sliced_desc* desc = malloc(sizeof(*desc)); + + desc->filter = filter; + desc->image = image; + desc->format = format; + desc->width = width; + desc->height = height; + + // Copy the LUT so that we can be frame-thread safe. + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); + memcpy( desc->rlut, self->rlut, sizeof(self->rlut) ); + memcpy( desc->glut, self->glut, sizeof(self->glut) ); + memcpy( desc->blut, self->blut, sizeof(self->blut) ); + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); + + mlt_slices_run_normal(0, sliced_proc, desc); + + free(desc); } static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) diff -Nru mlt-7.4.0/src/modules/plus/filter_lift_gamma_gain.yml mlt-7.6.0/src/modules/plus/filter_lift_gamma_gain.yml --- mlt-7.4.0/src/modules/plus/filter_lift_gamma_gain.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_lift_gamma_gain.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: lift_gamma_gain title: Lift, Gamma, and Gain @@ -30,6 +30,7 @@ minimum: 0.0 default: 0.0 mutable: yes + animation: yes - identifier: lift_g title: Lift Green @@ -37,6 +38,7 @@ minimum: 0.0 default: 0.0 mutable: yes + animation: yes - identifier: lift_b title: Lift Blue @@ -44,6 +46,7 @@ minimum: 0.0 default: 0.0 mutable: yes + animation: yes - identifier: gamma_r title: Gamma Red @@ -51,6 +54,7 @@ minimum: 0.0 default: 1.0 mutable: yes + animation: yes - identifier: gamma_g title: Gamma Green @@ -58,6 +62,7 @@ minimum: 0.0 default: 1.0 mutable: yes + animation: yes - identifier: gamma_b title: Gamma Blue @@ -65,6 +70,7 @@ minimum: 0.0 default: 1.0 mutable: yes + animation: yes - identifier: gain_r title: Gain Red @@ -72,6 +78,7 @@ minimum: 0.0 default: 1.0 mutable: yes + animation: yes - identifier: gain_g title: Gain Green @@ -79,6 +86,7 @@ minimum: 0.0 default: 1.0 mutable: yes + animation: yes - identifier: gain_b title: Gain Blue @@ -86,3 +94,4 @@ minimum: 0.0 default: 1.0 mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/plus/filter_lumakey.yml mlt-7.6.0/src/modules/plus/filter_lumakey.yml --- mlt-7.4.0/src/modules/plus/filter_lumakey.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_lumakey.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: lumakey title: Lumakey @@ -24,6 +24,7 @@ maximum: 255 default: 128 mutable: yes + animation: yes description: > Luma value that defines the center point of transition from prelevel to postlevel opacity value. @@ -35,6 +36,7 @@ maximum: 128 default: 0 mutable: yes + animation: yes description: > This defines the width of the transition from prelevel to postlevel luma value. Start point of transition in opacity value is threshold - slope and @@ -47,6 +49,7 @@ maximum: 255 default: 0 mutable: yes + animation: yes description: > Opacity value before the transition in opacity value begins. @@ -57,5 +60,6 @@ maximum: 255 default: 255 mutable: yes + animation: yes description: > Opacity value after the transition in opacity value ends. diff -Nru mlt-7.4.0/src/modules/plus/filter_pillar_echo.c mlt-7.6.0/src/modules/plus/filter_pillar_echo.c --- mlt-7.4.0/src/modules/plus/filter_pillar_echo.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_pillar_echo.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,449 +0,0 @@ -/* - * filter_pillar_echo.c -- filter to interpolate pixels outside an area of interest - * Copyright (c) 2020-2021 Meltytech, LLC - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include - -#include -#include - -/** Constrain a rect to be within the max dimensions -*/ -static mlt_rect constrain_rect( mlt_rect rect, int max_x, int max_y ) -{ - if ( rect.x < 0 ) - { - rect.w = rect.w + rect.x ; - rect.x = 0; - } - if ( rect.y < 0 ) - { - rect.h = rect.h + rect.y; - rect.y = 0; - } - if ( rect.x + rect.w < 0 ) - { - rect.w = 0; - } - if ( rect.y + rect.h < 0 ) - { - rect.h = 0; - } - if ( rect.x + rect.w > max_x ) - { - rect.w = max_x - rect.x; - } - if ( rect.y + rect.h > max_y ) - { - rect.h = max_y - rect.y; - } - return rect; -} - -/** Perform a bilinear scale from the rect inside the source to fill the destination - * - * \param src a pointer to the source image - * \param dst a pointer to the destination image - * \param width the number of values in each row - * \param height the number of values in each column - * \param rect the area of interest in the src to be scaled to fit the dst - */ - -static void bilinear_scale_rgba( uint8_t* src, uint8_t* dst, int width, int height, mlt_rect rect ) -{ - mlt_rect srcRect = rect; - - // Crop out a section of the rect that has the same aspect ratio as the image - double destAr = (double)width / (double)height; - double sourceAr = rect.w / rect.h; - if ( sourceAr > destAr ) - { - // Crop sides to fit height - srcRect.w = rect.w * destAr / sourceAr; - srcRect.x = rect.x + (rect.w - srcRect.w) / 2.0; - } - else if ( destAr > sourceAr ) - { - // Crop top and bottom to fit width. - srcRect.h = rect.h * sourceAr / destAr; - srcRect.y = rect.y + (rect.h - srcRect.h) / 2.0; - } - double srcScale = srcRect.h / (double)height; - int linesize = width * 4; - - int y = 0; - for ( y = 0; y < height; y++ ) - { - double srcY = srcRect.y + (double)y * srcScale; - int srcYindex = floor(srcY); - double fbottom = srcY - srcYindex; - double ftop = 1.0 - fbottom; - - int x = 0; - for ( x = 0; x < width; x++ ) - { - double srcX = srcRect.x + (double)x * srcScale; - int srcXindex = floor(srcX); - double fright = srcX - srcXindex; - double fleft = 1.0 - fright; - - double valueSum[] = {0.0, 0.0, 0.0, 0.0}; - double factorSum[] = {0.0, 0.0, 0.0, 0.0}; - - uint8_t* s = src + (srcYindex * linesize) + (srcXindex * 4); - - // Top Left - double ftl = ftop * fleft; - valueSum[0] += s[0] * ftl; - factorSum[0] += ftl; - valueSum[1] += s[1] * ftl; - factorSum[1] += ftl; - valueSum[2] += s[2] * ftl; - factorSum[2] += ftl; - valueSum[3] += s[3] * ftl; - factorSum[3] += ftl; - - // Top Right - if ( x < width - 1 ) - { - double ftr = ftop * fright; - valueSum[0] += s[4] * ftr; - factorSum[0] += ftr; - valueSum[1] += s[5] * ftr; - factorSum[1] += ftr; - valueSum[2] += s[6] * ftr; - factorSum[2] += ftr; - valueSum[3] += s[7] * ftr; - factorSum[3] += ftr; - } - - if( y < height - 1 ) - { - uint8_t* sb = s + linesize; - - // Bottom Left - double fbl = fbottom * fleft; - valueSum[0] += sb[0] * fbl; - factorSum[0] += fbl; - valueSum[1] += sb[1] * fbl; - factorSum[1] += fbl; - valueSum[2] += sb[2] * fbl; - factorSum[2] += fbl; - valueSum[3] += sb[3] * fbl; - factorSum[3] += fbl; - - // Bottom Right - if ( x < width - 1 ) - { - double fbr = fbottom * fright; - valueSum[0] += sb[4] * fbr; - factorSum[0] += fbr; - valueSum[1] += sb[5] * fbr; - factorSum[1] += fbr; - valueSum[2] += sb[6] * fbr; - factorSum[2] += fbr; - valueSum[3] += sb[7] * fbr; - factorSum[3] += fbr; - } - } - - dst[0] = (uint8_t)round( valueSum[0] / factorSum[0] ); - dst[1] = (uint8_t)round( valueSum[1] / factorSum[1] ); - dst[2] = (uint8_t)round( valueSum[2] / factorSum[2] ); - dst[3] = (uint8_t)round( valueSum[3] / factorSum[3] ); - dst += 4; - } - } -} - -/** Perform a box blur from the source to the destination - * - * src and dst can be the same location - * - * This function uses a sliding window accumulator method - applied - * horizontally first and then vertically. - * - * \param src a pointer to the source image - * \param dst a pointer to the destination image - * \param width the number of values in each row - * \param height the number of values in each column - * \param radius the radius of the box blur operation - */ - -static void box_blur( uint8_t* src, uint8_t* dst, int width, int height, int radius ) -{ - int accumulator[] = {0, 0, 0, 0}; - int x = 0; - int y = 0; - int step = 4; - int linesize = step * width; - uint8_t* d = NULL; - uint8_t* tmpbuff = mlt_pool_alloc( width * height * step ); - - if ( radius > (width / 2) ) - { - radius = width / 2; - } - if ( radius > (height / 2) ) - { - radius = height / 2; - } - - double diameter = (radius * 2) + 1; - - // Horizontal Blur - d = tmpbuff; - for ( y = 0; y < height; y++ ) - { - uint8_t* first = src + (y * linesize); - uint8_t* last = first + linesize - step; - uint8_t* s1 = first; - uint8_t* s2 = first; - accumulator[0] = first[0] * (radius + 1); - accumulator[1] = first[1] * (radius + 1); - accumulator[2] = first[2] * (radius + 1); - accumulator[3] = first[3] * (radius + 1); - - for ( x = 0; x < radius; x++ ) - { - accumulator[0] += s1[0]; - accumulator[1] += s1[1]; - accumulator[2] += s1[2]; - accumulator[3] += s1[3]; - s1 += step; - } - for ( x = 0; x <= radius; x++ ) - { - accumulator[0] += s1[0] - first[0]; - accumulator[1] += s1[1] - first[1]; - accumulator[2] += s1[2] - first[2]; - accumulator[3] += s1[3] - first[3]; - d[0] = lrint((double)accumulator[0] / diameter); - d[1] = lrint((double)accumulator[1] / diameter); - d[2] = lrint((double)accumulator[2] / diameter); - d[3] = lrint((double)accumulator[3] / diameter); - s1 += step; - d += step; - } - for ( x= radius + 1; x < width - radius; x++) - { - accumulator[0] += s1[0] - s2[0]; - accumulator[1] += s1[1] - s2[1]; - accumulator[2] += s1[2] - s2[2]; - accumulator[3] += s1[3] - s2[3]; - d[0] = lrint((double)accumulator[0] / diameter); - d[1] = lrint((double)accumulator[1] / diameter); - d[2] = lrint((double)accumulator[2] / diameter); - d[3] = lrint((double)accumulator[3] / diameter); - s1 += step; - s2 += step; - d += step; - } - for ( x = width - radius; x < width; x++ ) - { - accumulator[0] += last[0] - s2[0]; - accumulator[1] += last[1] - s2[1]; - accumulator[2] += last[2] - s2[2]; - accumulator[3] += last[3] - s2[3]; - d[0] = lrint((double)accumulator[0] / diameter); - d[1] = lrint((double)accumulator[1] / diameter); - d[2] = lrint((double)accumulator[2] / diameter); - d[3] = lrint((double)accumulator[3] / diameter); - s2 += step; - d += step; - } - } - - // Vertical Blur - for ( x = 0; x < width; x++ ) - { - uint8_t* first = tmpbuff + (x * step); - uint8_t* last = first + (linesize * (height - 1)); - uint8_t* s1 = first; - uint8_t* s2 = first; - d = dst + (x * step); - accumulator[0] = first[0] * (radius + 1); - accumulator[1] = first[1] * (radius + 1); - accumulator[2] = first[2] * (radius + 1); - accumulator[3] = first[3] * (radius + 1); - - for ( y = 0; y < radius; y++ ) - { - accumulator[0] += s1[0]; - accumulator[1] += s1[1]; - accumulator[2] += s1[2]; - accumulator[3] += s1[3]; - s1 += linesize; - } - for ( y = 0; y <= radius; y++ ) - { - accumulator[0] += s1[0] - first[0]; - accumulator[1] += s1[1] - first[1]; - accumulator[2] += s1[2] - first[2]; - accumulator[3] += s1[3] - first[3]; - d[0] = lrint((double)accumulator[0] / diameter); - d[1] = lrint((double)accumulator[1] / diameter); - d[2] = lrint((double)accumulator[2] / diameter); - d[3] = lrint((double)accumulator[3] / diameter); - s1 += linesize; - d += linesize; - } - for ( y = radius + 1; y < height - radius; y++) - { - accumulator[0] += s1[0] - s2[0]; - accumulator[1] += s1[1] - s2[1]; - accumulator[2] += s1[2] - s2[2]; - accumulator[3] += s1[3] - s2[3]; - d[0] = lrint((double)accumulator[0] / diameter); - d[1] = lrint((double)accumulator[1] / diameter); - d[2] = lrint((double)accumulator[2] / diameter); - d[3] = lrint((double)accumulator[3] / diameter); - s1 += linesize; - s2 += linesize; - d += linesize; - } - for ( y = height - radius; y < height; y++ ) - { - accumulator[0] += last[0] - s2[0]; - accumulator[1] += last[1] - s2[1]; - accumulator[2] += last[2] - s2[2]; - accumulator[3] += last[3] - s2[3]; - d[0] = lrint((double)accumulator[0] / diameter); - d[1] = lrint((double)accumulator[1] / diameter); - d[2] = lrint((double)accumulator[2] / diameter); - d[3] = lrint((double)accumulator[3] / diameter); - s2 += linesize; - d += linesize; - } - } - - mlt_pool_release( tmpbuff ); -} - -/** Copy pixels from source to destination - * - * \param src a pointer to the source image - * \param dst a pointer to the destination image - * \param width the number of values in each row - * \param rect the area of interest in the src to be copied to the dst - */ - -static void blit_rect( uint8_t* src, uint8_t* dst, int width, mlt_rect rect ) -{ - int blitHeight = rect.h; - int blitWidth = rect.w * 4; - int linesize = width * 4; - src += (int)rect.y * linesize + (int)rect.x * 4; - dst += (int)rect.y * linesize + (int)rect.x * 4; - while ( blitHeight-- ) - { - memcpy( dst, src, blitWidth ); - src += linesize; - dst += linesize; - } -} - -static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) -{ - int error = 0; - mlt_filter filter = (mlt_filter)mlt_frame_pop_service( frame ); - mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); - char* rect_str = mlt_properties_get( filter_properties, "rect" ); - if ( !rect_str ) - { - mlt_log_warning( MLT_FILTER_SERVICE(filter), "rect property not set\n" ); - return mlt_frame_get_image( frame, image, format, width, height, writable ); - } - mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); - mlt_position position = mlt_filter_get_position( filter, frame ); - mlt_position length = mlt_filter_get_length2( filter, frame ); - mlt_rect rect = mlt_properties_anim_get_rect( filter_properties, "rect", position, length ); - if ( strchr( rect_str, '%' ) ) - { - rect.x *= profile->width; - rect.w *= profile->width; - rect.y *= profile->height; - rect.h *= profile->height; - } - double scale = mlt_profile_scale_width( profile, *width ); - rect.x *= scale; - rect.w *= scale; - scale = mlt_profile_scale_height( profile, *height ); - rect.y *= scale; - rect.h *= scale; - rect = constrain_rect( rect, profile->width * scale, profile->height * scale ); - - if ( rect.w < 1 || rect.h < 1 ) - { - mlt_log_info( MLT_FILTER_SERVICE(filter), "rect invalid\n" ); - return mlt_frame_get_image( frame, image, format, width, height, writable ); - } - - *format = mlt_image_rgba; - error = mlt_frame_get_image( frame, image, format, width, height, 1 ); - - if (error) return error; - if (rect.x <= 0 && rect.y <= 0 && rect.w >= *width && rect.h >= *height) - { - // Rect fills the image. Nothing to blur - return error; - } - - double blur = mlt_properties_anim_get_int( filter_properties, "blur", position, length ); - // Convert from percent to pixels. - blur = blur * (double)profile->width * mlt_profile_scale_width( profile, *width ) / 100.0; - blur = lrint(blur); - - int size = mlt_image_format_size( *format, *width, *height, NULL ); - uint8_t* dst = mlt_pool_alloc( size ); - - bilinear_scale_rgba( *image, dst, *width, *height, rect ); - box_blur( dst, dst, *width, *height, blur ); - blit_rect( *image, dst, *width, rect ); - - *image = dst; - mlt_frame_set_image( frame, dst, size, mlt_pool_release ); - - return error; -} - -static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) -{ - mlt_frame_push_service( frame, filter ); - mlt_frame_push_get_image( frame, filter_get_image ); - return frame; -} - -mlt_filter filter_pillar_echo_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - mlt_filter filter = mlt_filter_new(); - - if ( filter ) - { - mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); - mlt_properties_set( properties, "rect", "0% 0% 10% 10%" ); - mlt_properties_set_double( properties, "blur", 4.0 ); - filter->process = filter_process; - } - else - { - mlt_log_error( NULL, "Filter pillar_echo initialization failed\n" ); - } - return filter; -} diff -Nru mlt-7.4.0/src/modules/plus/filter_pillar_echo.yml mlt-7.6.0/src/modules/plus/filter_pillar_echo.yml --- mlt-7.4.0/src/modules/plus/filter_pillar_echo.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_pillar_echo.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -schema_version: 0.1 -type: filter -identifier: pillar_echo -title: Pillar Echo -version: 1 -copyright: Meltytech, LLC -license: LGPLv2.1 -language: en -tags: - - Video -description: > - Create an echo effect (blur) outside of an area of interest. - - The area of interest is scaled to fill the image, then blurred. Then the - original image is replaced back on top. -parameters: - - identifier: rect - title: Rectangle - description: > - Defines the rectangle of the area of interest. - - Format is: "X Y W H". - - X, Y, W, H are assumed to be pixel units unless they have the suffix '%'. - type: rect - default: "0 0 10% 10%" - readonly: no - mutable: yes - - - identifier: blur - title: Blur - description: > - The blur radius as a percent of the image width - type: float - default: 4.0 - readonly: no - mutable: yes \ No newline at end of file diff -Nru mlt-7.4.0/src/modules/plus/filter_sepia.c mlt-7.6.0/src/modules/plus/filter_sepia.c --- mlt-7.4.0/src/modules/plus/filter_sepia.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_sepia.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_sepia.c -- sepia filter - * Copyright (C) 2003-2014 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,21 +19,48 @@ #include #include +#include #include #include #include -/** Do it :-). -*/ +typedef struct { + uint8_t* image; + int height; + int width; + uint8_t u; + uint8_t v; +} slice_desc; + +static int do_slice_proc(int id, int index, int jobs, void* data) +{ + (void) id; // unused + slice_desc* desc = (slice_desc*) data; + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, desc->height, &slice_line_start); + int slice_line_end = slice_line_start + slice_height; + int line_size = desc->width * 2; + int uneven = desc->width % 2; + int x,y; + for ( y = slice_line_start; y < slice_line_end; y++) + { + uint8_t* p = desc->image + y * line_size; + for ( x = 0; x < line_size; x += 4) + { + p[x+1] = desc->u; + p[x+3] = desc->v; + } + if ( uneven ) + { + p[line_size - 1] = desc->u; + } + } +} static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter mlt_filter filter = mlt_frame_pop_service( frame ); - mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); - mlt_position position = mlt_filter_get_position( filter, frame ); - mlt_position length = mlt_filter_get_length2( filter, frame ); // Get the image *format = mlt_image_yuv422; @@ -42,34 +69,16 @@ // Only process if we have no error and a valid colour space if ( error == 0 && *image ) { - // We modify the whole image - uint8_t *p = *image; - int h = *height; - int uneven = *width % 2; - int w = ( *width - uneven ) / 2; - int t; - - // Get u and v values - int u = mlt_properties_anim_get_int( properties, "u", position, length ); - int v = mlt_properties_anim_get_int( properties, "v", position, length ); - - // Loop through image - while( h -- ) - { - t = w; - while( t -- ) - { - p ++; - *p ++ = u; - p ++; - *p ++ = v; - } - if ( uneven ) - { - p ++; - *p ++ = u; - } - } + mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); + mlt_position position = mlt_filter_get_position( filter, frame ); + mlt_position length = mlt_filter_get_length2( filter, frame ); + slice_desc desc; + desc.image = *image; + desc.height = *height; + desc.width = *width; + desc.u = mlt_properties_anim_get_int( properties, "u", position, length ); + desc.v = mlt_properties_anim_get_int( properties, "v", position, length ); + mlt_slices_run_normal(0, do_slice_proc, &desc); } return error; diff -Nru mlt-7.4.0/src/modules/plus/filter_sepia.yml mlt-7.6.0/src/modules/plus/filter_sepia.yml --- mlt-7.4.0/src/modules/plus/filter_sepia.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_sepia.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: sepia title: Sepia @@ -18,6 +18,8 @@ minimum: 0 maximum: 255 default: 75 + mutable: yes + animation: yes - identifier: v type: integer @@ -25,3 +27,5 @@ minimum: 0 maximum: 255 default: 150 + mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/plus/filter_shape.c mlt-7.6.0/src/modules/plus/filter_shape.c --- mlt-7.4.0/src/modules/plus/filter_shape.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_shape.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,8 +1,6 @@ /* * filter_shape.c -- Arbitrary alpha channel shaping - * Copyright (C) 2005 Visual Media Fx Inc. - * Copyright (C) 2021 Meltytech, LLC - * Author: Charles Yates + * Copyright (C) 2008-2022 Meltytech, LLC * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -25,6 +23,20 @@ #include #include +typedef struct +{ + uint8_t *alpha; + uint8_t *mask; + int width; + int height; + double softness; + double mix; + int invert; + int invert_mask; + double offset; + double divisor; +} slice_desc; + static inline double smoothstep( const double e1, const double e2, const double a ) { if ( a < e1 ) return 0.0; @@ -33,6 +45,52 @@ return ( v * v * ( 3 - 2 * v ) ); } + +static int slice_alpha_proc(int id, int index, int jobs, void* data) +{ + (void) id; // unused + slice_desc* desc = ((slice_desc*) data); + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, desc->height, &slice_line_start); + int size = desc->width * slice_height + 1; + uint8_t *p = desc->alpha + slice_line_start * desc->width; + uint8_t *q = desc->mask + slice_line_start * desc->width; + double a = 0; + double b = 0; + + while (--size) { + a = (double)(*q++ ^ desc->invert_mask) / desc->divisor; + b = 1.0 - smoothstep(a, a + desc->softness, desc->mix); + *p = (uint8_t)(*p * b) ^ desc->invert; + p++; + } + + return 0; +} + +static int slice_luma_proc(int id, int index, int jobs, void* data) +{ + (void) id; // unused + slice_desc* desc = ((slice_desc*) data); + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, desc->height, &slice_line_start); + int size = desc->width * slice_height + 1; + uint8_t *p = desc->alpha + slice_line_start * desc->width; + uint8_t *q = desc->mask + slice_line_start * desc->width * 2; + double a = 0; + double b = 0; + + while (--size) { + a = ((double)(*q ^ desc->invert_mask) - desc->offset) / desc->divisor; + b = smoothstep(a, a + desc->softness, desc->mix); + *p = (uint8_t )(*p * b) ^ desc->invert; + p++; + q += 2; + } + + return 0; +} + + + /** Get the images and apply the luminance of the mask to the alpha of the frame. */ @@ -48,6 +106,7 @@ int use_luminance = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "use_luminance" ); int use_mix = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "use_mix" ); int invert = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "invert" ) * 255; + int invert_mask = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "invert_mask" ) * 255; if (mlt_properties_get_int(MLT_FILTER_PROPERTIES(filter), "reverse")) { mix = 1.0 - mix; @@ -58,13 +117,13 @@ *format = mlt_image_yuv422; *width -= *width % 2; if ( mlt_frame_get_image( frame, image, format, width, height, 1 ) == 0 && - ( !use_luminance || !use_mix || (int) mix != 1 || invert == 255 ) ) + (!use_luminance || !use_mix || (int) mix != 1 || invert == 255 || invert_mask == 255) ) { // Obtain a scaled/distorted mask to match uint8_t *mask_img = NULL; mlt_image_format mask_fmt = mlt_image_yuv422; mlt_properties_set_int( MLT_FRAME_PROPERTIES( mask ), "distort", 1 ); - mlt_properties_pass_list( MLT_FRAME_PROPERTIES( mask ), MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace, deinterlace_method, rescale.interp, consumer_tff, consumer_color_trc" ); + mlt_properties_copy(MLT_FRAME_PROPERTIES(mask), MLT_FRAME_PROPERTIES(frame), "consumer."); if ( mlt_frame_get_image( mask, &mask_img, &mask_fmt, width, height, 0 ) == 0 ) { @@ -92,13 +151,19 @@ } if ( use_mix ) { - while( size -- ) - { - a = ( double )*q ++ / 255.0; - b = 1.0 - smoothstep( a, a + softness, mix ); - *p = ( uint8_t )( *p * b ) ^ invert; - p ++; - } + slice_desc desc = { + .alpha = p, + .mask = q, + .width = *width, + .height = *height, + .softness = softness, + .mix = mix, + .invert = invert, + .invert_mask = invert_mask, + .offset = 0.0, + .divisor = 255.0 + }; + mlt_slices_run_normal(0, slice_alpha_proc, &desc); } else { @@ -112,27 +177,27 @@ uint8_t *q = mask_img; while( size -- ) { - *p = *q; + *p = *q ^ invert_mask; p++; q += 2; } } - else if ( (int) mix != 1 || invert == 255 ) + else if ((int) mix != 1 || invert == 255 || invert_mask == 255) { - int full_range = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "full_luma" ); - double offset = full_range ? 0.0 : 16.0; - double divisor = full_range ? 255.0 : 235.0; - uint8_t *q = mask_img; - // Ensure softness tends to zero as mix tends to 1 - softness *= ( 1.0 - mix ); - while( size -- ) - { - a = ( ( double ) *q - offset ) / divisor; - b = smoothstep( a, a + softness, mix ); - *p = ( uint8_t )( *p * b ) ^ invert; - p ++; - q += 2; - } + int full_range = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "full_range" ); + slice_desc desc = { + .alpha = p, + .mask = mask_img, + .width = *width, + .height = *height, + .softness = softness * (1.0 - mix), + .mix = mix, + .invert = invert, + .invert_mask = invert_mask, + .offset = full_range ? 0.0 : 16.0, + .divisor = full_range ? 255.0 : 235.0 + }; + mlt_slices_run_normal(0, slice_luma_proc, &desc); } } } diff -Nru mlt-7.4.0/src/modules/plus/filter_shape.yml mlt-7.6.0/src/modules/plus/filter_shape.yml --- mlt-7.4.0/src/modules/plus/filter_shape.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_shape.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,9 +1,8 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: shape title: Shape Alpha -version: 4 -copyright: Visual Media FX ? +version: 5 creator: Charles Yates license: LGPLv2.1 language: en @@ -32,6 +31,7 @@ maximum: 100 default: 100 mutable: yes + animation: yes - identifier: softness title: Softness @@ -48,14 +48,23 @@ - identifier: invert title: Invert type: boolean - description: Use the inverse of the alpha or luma value. + description: Invert the resulting alpha channel. + default: no + mutable: yes + + - identifier: invert_mask + title: Invert Mask + description: Use the inverse of the resource's alpha channel or luma value. + type: boolean default: no mutable: yes - identifier: reverse title: Reverse type: boolean - description: Use the complement of the mix level. + description: > + Use the complement of the mix level. This also inverts the output alpha, + which is probably not what you want. See also invert_mask. default: no mutable: yes diff -Nru mlt-7.4.0/src/modules/plus/filter_spot_remover.c mlt-7.6.0/src/modules/plus/filter_spot_remover.c --- mlt-7.4.0/src/modules/plus/filter_spot_remover.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_spot_remover.c 2022-04-19 08:45:42.000000000 +0000 @@ -79,19 +79,29 @@ return rect; } +typedef struct +{ + uint8_t* chan[4]; // pointer to the first value in the channel + int rowCount[4]; // the number of values in each line (row) + int step[4]; // the space between values in each line + mlt_rect rect[4]; // rect the area to be removed +} slice_desc; + /** Perform spot removal on a channel. * * Values within the rectangle are replaced with interpolated values. * Each value is an interpolation of the first values outside of the rect on * the top, bottom, left and right of the value being interpolated. - * - * \param chan a pointer to the first value in the channel - * \param rowCount the number of values in each line (row) - * \param step the space between values in each line - * \param rect the area to be removed */ -static void remove_spot_channel( uint8_t *chan, int rowCount, int step, mlt_rect rect ) +static int remove_spot_channel_proc(int id, int index, int jobs, void* data) { + (void) id; // unused + (void) jobs; // unused + slice_desc* desc = ((slice_desc*) data); + uint8_t *chan = desc->chan[index]; + int rowCount = desc->rowCount[index]; + int step = desc->step[index]; + mlt_rect rect = desc->rect[index]; int yStop = rect.y + rect.h; int xStop = rect.x + rect.w; int rowSize = rowCount * step; @@ -171,40 +181,67 @@ struct mlt_image_s img; mlt_image_set_values( &img, *image, *format, *width, *height ); + // Process each plane in a separate thread. int i; + slice_desc desc; + int jobs = 0; switch( *format ) { case mlt_image_rgba: + jobs = 4; for ( i = 0; i < 4; i++ ) { - remove_spot_channel( img.planes[0] + i, img.width, 4, rect ); + desc.chan[i] = img.planes[0] + i; + desc.rowCount[i] = img.width; + desc.step[i] = 4; + desc.rect[i] = rect; } break; case mlt_image_rgb: + jobs = 3; for ( i = 0; i < 3; i++ ) { - remove_spot_channel( img.planes[0] + i, img.width, 3, rect ); + desc.chan[i] = img.planes[0] + i; + desc.rowCount[i] = img.width; + desc.step[i] = 4; + desc.rect[i] = rect; } break; case mlt_image_yuv422: + jobs = 3; // Y - remove_spot_channel( img.planes[0], img.width, 2, rect ); + desc.chan[0] = img.planes[0]; + desc.rowCount[0] = img.width; + desc.step[0] = 2; + desc.rect[0] = rect; // U - remove_spot_channel( img.planes[0] + 1, img.width / 2, 4, - constrain_rect( scale_rect( rect, 2, 1 ), img.width / 2, img.height ) ); + desc.chan[1] = img.planes[0] + 1; + desc.rowCount[1] = img.width / 2; + desc.step[1] = 4; + desc.rect[1] = constrain_rect( scale_rect( rect, 2, 1 ), img.width / 2, img.height ); // V - remove_spot_channel( img.planes[0] + 3, img.width / 2, 4, - constrain_rect( scale_rect( rect, 2, 1 ), img.width / 2, img.height ) ); + desc.chan[2] = img.planes[0] + 3; + desc.rowCount[2] = img.width / 2; + desc.step[2] = 4; + desc.rect[2] = constrain_rect( scale_rect( rect, 2, 1 ), img.width / 2, img.height ); break; case mlt_image_yuv420p: + jobs = 3; // Y - remove_spot_channel( img.planes[0], img.width, 1, rect ); + desc.chan[0] = img.planes[0]; + desc.rowCount[0] = img.width; + desc.step[0] = 1; + desc.rect[0] = rect; // U - remove_spot_channel( img.planes[1], img.width / 2, 1, - constrain_rect( scale_rect( rect, 2, 2 ), img.width / 2, img.height / 2 ) ); + desc.chan[1] = img.planes[1]; + desc.rowCount[1] = img.width / 2; + desc.step[1] = 1; + desc.rect[1] = constrain_rect( scale_rect( rect, 2, 2 ), img.width / 2, img.height / 2 ); // V - remove_spot_channel( img.planes[2], img.width / 2, 1, - constrain_rect( scale_rect( rect, 2, 2 ), img.width / 2, img.height / 2 ) ); + desc.chan[2] = img.planes[2]; + desc.rowCount[2] = img.width / 2; + desc.step[2] = 1; + desc.rect[2] = constrain_rect( scale_rect( rect, 2, 2 ), img.width / 2, img.height / 2 ); break; default: return 1; @@ -213,9 +250,15 @@ uint8_t *alpha = mlt_frame_get_alpha( frame ); if ( alpha && *format != mlt_image_rgba ) { - remove_spot_channel( alpha, *width, 1, rect ); + jobs++; + desc.chan[3] = alpha; + desc.rowCount[3] = img.width; + desc.step[3] = 1; + desc.rect[3] = rect; } + mlt_slices_run_normal(jobs, remove_spot_channel_proc, &desc); + return error; } diff -Nru mlt-7.4.0/src/modules/plus/filter_spot_remover.yml mlt-7.6.0/src/modules/plus/filter_spot_remover.yml --- mlt-7.4.0/src/modules/plus/filter_spot_remover.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_spot_remover.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: spot_remover title: Spot Remover @@ -26,3 +26,4 @@ default: "0 0 10% 10%" readonly: no mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/plus/filter_strobe.yml mlt-7.6.0/src/modules/plus/filter_strobe.yml --- mlt-7.4.0/src/modules/plus/filter_strobe.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_strobe.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: strobe title: Alpha strobing @@ -17,6 +17,7 @@ description: Whether to invert which frames are on and which is off default: 0 mutable: yes + animation: yes - identifier: interval title: Interval @@ -28,4 +29,5 @@ maximum: 100 readonly: no mutable: yes + animation: yes widget: spinner diff -Nru mlt-7.4.0/src/modules/plus/filter_text.c mlt-7.6.0/src/modules/plus/filter_text.c --- mlt-7.4.0/src/modules/plus/filter_text.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_text.c 2022-04-19 08:45:42.000000000 +0000 @@ -128,7 +128,7 @@ // Set the b_frame to be in the same position and have same consumer requirements mlt_frame_set_position( b_frame, position ); - mlt_properties_set_int( b_props, "consumer_deinterlace", mlt_properties_get_int( a_props, "consumer_deinterlace" ) ); + mlt_properties_set_int( b_props, "consumer.progressive", mlt_properties_get_int( a_props, "consumer.progressive" ) ); mlt_properties_set_double( b_props, "consumer_scale", mlt_properties_get_double( a_props, "consumer_scale" ) ); // Apply all filters that are attached to this filter to the b frame diff -Nru mlt-7.4.0/src/modules/plus/filter_text.yml mlt-7.6.0/src/modules/plus/filter_text.yml --- mlt-7.4.0/src/modules/plus/filter_text.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_text.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: text title: Text @@ -27,6 +27,8 @@ type: rect description: A set of X/Y coordinates by which to adjust the text. default: 0%/0%:100%x100%:100 + mutable: yes + animation: yes - identifier: family title: Font family diff -Nru mlt-7.4.0/src/modules/plus/filter_threshold.c mlt-7.6.0/src/modules/plus/filter_threshold.c --- mlt-7.4.0/src/modules/plus/filter_threshold.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_threshold.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,8 +1,6 @@ /* * filter_threshold.c -- Arbitrary alpha channel shaping - * Copyright (C) 2005 Visual Media Fx Inc. - * Copyright (C) 2021 Meltytech, LLC - * Author: Charles Yates + * Copyright (C) 2008-2022 Meltytech, LLC * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -24,6 +22,69 @@ #include #include #include +#include + +typedef struct { + int midpoint; + int use_alpha; + int invert; + int full_luma; + uint8_t* image; + uint8_t* alpha; + int width; + int height; +} slice_desc; + +static int do_slice_proc(int id, int index, int jobs, void* data) +{ + (void) id; // unused + slice_desc* desc = (slice_desc*) data; + int slice_line_start, slice_height = mlt_slices_size_slice(jobs, index, desc->height, &slice_line_start); + int slice_line_end = slice_line_start + slice_height; + int size = desc->width * slice_height * 2; + uint8_t white = desc->full_luma? 255 : 235; + uint8_t black = desc->full_luma? 0 : 16; + uint8_t A = desc->invert? white : black; + uint8_t B = desc->invert? black : white; + uint8_t* p = desc->image + (slice_line_start * desc->width * 2); + int i = 0; + + if ( !desc->use_alpha ) + { + for (i = 0; i < size; i += 2) + { + if ( p[i] < desc->midpoint ) + p[i] = A; + else + p[i] = B; + p[i+1] = 128; + } + } + else + { + + if ( desc->alpha ) + { + uint8_t *alpha = desc->alpha + (slice_line_start * desc->width); + for (i = 0; i < size; i += 2) + { + if ( alpha[i/2] < desc->midpoint ) + p[i] = A; + else + p[i] = B; + p[i+1] = 128; + } + } + else + { + for (i = 0; i < size; i += 2) + { + p[i] = B; + p[i+1] = 128; + } + } + } +} /** Get the images and apply the luminance of the mask to the alpha of the frame. */ @@ -36,54 +97,23 @@ *format = mlt_image_yuv422; if ( mlt_frame_get_image( frame, image, format, width, height, writable ) == 0 ) { + slice_desc desc; mlt_properties properties = mlt_filter_properties(filter); mlt_position position = mlt_filter_get_position(filter, frame); mlt_position length = mlt_filter_get_length2(filter, frame); - int midpoint = mlt_properties_anim_get_int(properties, "midpoint", position, length); - int use_alpha = mlt_properties_get_int(properties, "use_alpha"); - int invert = mlt_properties_get_int(properties, "invert"); - int full_luma = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), "full_luma"); - uint8_t white = full_luma? 255 : 235; - uint8_t black = full_luma? 0 : 16; - uint8_t *p = *image; - uint8_t A = invert? white : black; - uint8_t B = invert? black : white; - int size = *width * *height + 1; - - if ( !use_alpha ) + desc.midpoint = mlt_properties_anim_get_int(properties, "midpoint", position, length); + desc.use_alpha = mlt_properties_get_int(properties, "use_alpha"); + desc.invert = mlt_properties_get_int(properties, "invert"); + desc.full_luma = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), "full_luma"); + desc.image = *image; + desc.alpha = NULL; + desc.width = *width; + desc.height = *height; + if ( desc.use_alpha ) { - while (--size) - { - if ( *p < midpoint ) - *p ++ = A; - else - *p ++ = B; - *p ++ = 128; - } - } - else - { - uint8_t *alpha = mlt_frame_get_alpha( frame ); - if ( alpha ) - { - while (--size) - { - if ( *alpha ++ < midpoint ) - *p ++ = A; - else - *p ++ = B; - *p ++ = 128; - } - } - else - { - while (--size) - { - *p ++ = B; - *p ++ = 128; - } - } + desc.alpha = mlt_frame_get_alpha( frame ); } + mlt_slices_run_normal(0, do_slice_proc, &desc); } return 0; diff -Nru mlt-7.4.0/src/modules/plus/filter_threshold.yml mlt-7.6.0/src/modules/plus/filter_threshold.yml --- mlt-7.4.0/src/modules/plus/filter_threshold.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/filter_threshold.yml 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,6 @@ identifier: threshold title: Threshold version: 2 -copyright: Visual Media FX ? creator: Charles Yates license: LGPLv2.1 language: en @@ -31,7 +30,7 @@ - identifier: invert title: Invert type: integer - description: Wether to swap black and white + description: Whether to swap black and white mutable: yes default: 0 widget: checkbox diff -Nru mlt-7.4.0/src/modules/plus/interp.h mlt-7.6.0/src/modules/plus/interp.h --- mlt-7.4.0/src/modules/plus/interp.h 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/interp.h 2022-04-19 08:45:42.000000000 +0000 @@ -1,7 +1,7 @@ //interp.c /* * Copyright (C) 2010 Marko Cebokli http://lea.hamradio.si/~s57uuu - * This file is a part of the Frei0r plugin "c0rners" + * Copyright (C) 2010-2022 Meltytech, LLC * * 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 @@ -18,37 +18,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/******************************************************************* - * The remapping functions use a map array, which contains a pair - * of floating values fo each pixel of the output image. These - * represent the location in the input image, from where the value - * of the given output pixel should be interpolated. - * They are given in pixels of the input image. - * If the output image is wo pixels wide, then the x coordinate - * of the pixel in row r and column c is at 2*(r*wo+c) in the map - * array, and y at 2*(r*wo+c)+1 - * - * The map array is usually computation intensive to generate, and - * he purpose of the map array is to allow fast remapping of - * several images (video) using the same map array. - ******************************************************************/ - - -//compile: gcc -c -O2 -Wall -std=c99 -fPIC interp.c -o interp.o - -// -std=c99 za rintf() -// -fPIC da lahko linkas v .so (za frei0r) - #include -#include /* za debug printoute */ +#include #include - //#define TEST_XY_LIMITS //-------------------------------------------------------- -//pointer to an interpolating function -//parameters: +// pointer to an interpolating function +// parameters: // source image // source width // source height @@ -57,108 +35,32 @@ // opacity // destination image // flag to overwrite alpha channel -typedef int (*interpp)(unsigned char*, int, int, float, float, float, unsigned char*, int); - -//************************************** -//HERE BEGIN THE INTERPOLATION FUNCTIONS - -//------------------------------------------------------ -//za debugging - z izpisovanjem -//interpolacija "najblizji sosed" (ni prava interpolacija) -//za byte (char) vrednosti -// *sl vhodni array (slika) -// w,h dimenzija slike je wxh -// x,y tocka, za katero izracuna interpolirano vrednost -// o opacity -// *v interpolirana vrednost -int interpNNpr_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) -{ - //printf("u=%5.2f v=%5.2f ",x,y); - printf("u=%5.3f v=%5.3f ",x/(w-1),y/(h-1)); - //printf("U=%2d V=%2d ",(int)rintf(x),(int)rintf(y)); - -#ifdef TEST_XY_LIMITS - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; -#endif - *v=sl[(int)rintf(x)+(int)rintf(y)*w]; - return 0; -} - -//------------------------------------------------------ -//interpolacija "najblizji sosed" (ni prava interpolacija) -//za byte (char) vrednosti -// *sl vhodni array (slika) -// w,h dimenzija slike je wxh -// x,y tocka, za katero izracuna interpolirano vrednost -// o opacity -// *v interpolirana vrednost -int interpNN_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) -{ -#ifdef TEST_XY_LIMITS - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; -#endif +typedef int (*interpp)(unsigned char*, int, int, float, float, float, unsigned char*, int); - *v=sl[(int)rintf(x)+(int)rintf(y)*w]; - return 0; -} +// nearest neighbor -//------------------------------------------------------ -//interpolacija "najblizji sosed" (ni prava interpolacija) -//za byte (char) vrednosti v packed color 32 bitnem formatu -//little endian !! -// *sl vhodni array (slika) -// w,h dimenzija slike je wxh -// x,y tocka, za katero izracuna interpolirano vrednost -// o opacity -// *v interpolirana vrednost -int interpNN_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) +int interpNN_b32(unsigned char *s, int w, int h, float x, float y, float o, unsigned char *d, int is_atop) { #ifdef TEST_XY_LIMITS if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; #endif int p = (int) rintf(x) * 4 + (int) rintf(y) * 4 * w; - float alpha_sl = (float) sl[p + 3] / 255.0f * o; - float alpha_v = (float) v[3] / 255.0f; - float alpha = alpha_sl + alpha_v - alpha_sl * alpha_v; - v[3] = is_atop? sl[p + 3] : (255 * alpha); - alpha = alpha_sl / alpha; - v[0] = v[0] * (1.0f - alpha) + sl[p] * alpha; - v[1] = v[1] * (1.0f - alpha) + sl[p + 1] * alpha; - v[2] = v[2] * (1.0f - alpha) + sl[p + 2] * alpha; + float alpha_s = (float) s[p + 3] / 255.0f * o; + float alpha_d = (float) d[3] / 255.0f; + float alpha = alpha_s + alpha_d - alpha_s * alpha_d; + d[3] = is_atop? s[p + 3] : (255 * alpha); + alpha = alpha_s / alpha; + d[0] = d[0] * (1.0f - alpha) + s[p] * alpha; + d[1] = d[1] * (1.0f - alpha) + s[p + 1] * alpha; + d[2] = d[2] * (1.0f - alpha) + s[p + 2] * alpha; return 0; } -//------------------------------------------------------ -//bilinearna interpolacija -//za byte (char) vrednosti -// *sl vhodni array (slika) -// w,h dimenzija slike je wxh -// x,y tocka, za katero izracuna interpolirano vrednost -// o opacity -// *v interpolirana vrednost -int interpBL_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) -{ - int m,n,k,l; - float a,b; +// bilinear -#ifdef TEST_XY_LIMITS - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; -#endif - - m=(int)floorf(x); n=(int)floorf(y); - k=n*w+m; l=(n+1)*w+m; - a=sl[k]+(sl[k+1]-sl[k])*(x-(float)m); - b=sl[l]+(sl[l+1]-sl[l])*(x-(float)m); - *v=a+(b-a)*(y-(float)n); - return 0; -} - -//------------------------------------------------------ -//bilinearna interpolacija -//za byte (char) vrednosti v packed color 32 bitnem formatu -int interpBL_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) +int interpBL_b32(unsigned char *s, int w, int h, float x, float y, float o, unsigned char *d, int is_atop) { int m,n,k,l,n1,l1,k1; float a,b; @@ -167,101 +69,45 @@ if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; #endif - m=(int)floorf(x); + m = (int)floorf(x); if (m + 2 > w) m = w - 2; - n=(int)floorf(y); + n = (int)floorf(y); if (n + 2 > h) n = h - 2; - k=n*w+m; l=(n+1)*w+m; - k1=4*(k+1); l1=4*(l+1); n1=4*((n+1)*w+m); - l=4*l; k=4*k; - - a=sl[k+3]+(sl[k1+3]-sl[k+3])*(x-(float)m); - b=sl[l+3]+(sl[l1+3]-sl[n1+3])*(x-(float)m); - - - float alpha_sl = a+(b-a)*(y-(float)n); - float alpha_v = (float) v[3] / 255.0f; - if (is_atop) v[3] = alpha_sl; - alpha_sl = alpha_sl / 255.0f * o; - float alpha = alpha_sl + alpha_v - alpha_sl * alpha_v; - if (!is_atop) v[3] = 255 * alpha; - alpha = alpha_sl / alpha; - - a=sl[k]+(sl[k1]-sl[k])*(x-(float)m); - b=sl[l]+(sl[l1]-sl[n1])*(x-(float)m); - v[0]= v[0] * (1.0f - alpha) + (a+(b-a)*(y-(float)n)) * alpha; - - a=sl[k+1]+(sl[k1+1]-sl[k+1])*(x-(float)m); - b=sl[l+1]+(sl[l1+1]-sl[n1+1])*(x-(float)m); - v[1]= v[1] * (1.0f - alpha) + (a+(b-a)*(y-(float)n)) * alpha; - - a=sl[k+2]+(sl[k1+2]-sl[k+2])*(x-(float)m); - b=sl[l+2]+(sl[l1+2]-sl[n1+2])*(x-(float)m); - v[2]= v[2] * (1.0f - alpha) + (a+(b-a)*(y-(float)n)) * alpha; - - return 0; -} - -//------------------------------------------------------ -//bikubicna interpolacija "smooth" -//za byte (char) vrednosti -//kar Aitken-Neville formula iz Bronstajna -// *sl vhodni array (slika) -// w,h dimenzija slike je wxh -// x,y tocka, za katero izracuna interpolirano vrednost -// o opacity -// *v interpolirana vrednost -int interpBC_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) -{ - int i,j,l,m,n; - float k; - float p[4],p1[4],p2[4],p3[4],p4[4]; + k = n*w+m; l = (n+1)*w+m; + k1 = 4*(k+1); l1 = 4*(l+1); n1 = 4*((n+1)*w+m); + l = 4*l; k = 4*k; -#ifdef TEST_XY_LIMITS - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; -#endif + a = s[k+3]+(s[k1+3]-s[k+3])*(x-(float)m); + b = s[l+3]+(s[l1+3]-s[n1+3])*(x-(float)m); - m=(int)ceilf(x)-2; if (m<0) m=0; if ((m+5)>w) m=w-4; - n=(int)ceilf(y)-2; if (n<0) n=0; if ((n+5)>h) n=h-4; - //njaprej po y (stiri stolpce) - for (i=0;i<4;i++) - { - l=m+(i+n)*w; - p1[i]=sl[l]; - p2[i]=sl[l+1]; - p3[i]=sl[l+2]; - p4[i]=sl[l+3]; - } - for (j=1;j<4;j++) - for (i=3;i>=j;i--) - { - k=(y-i-n)/j; - p1[i]=p1[i]+k*(p1[i]-p1[i-1]); - p2[i]=p2[i]+k*(p2[i]-p2[i-1]); - p3[i]=p3[i]+k*(p3[i]-p3[i-1]); - p4[i]=p4[i]+k*(p4[i]-p4[i-1]); - } + float alpha_s = a+(b-a)*(y-(float)n); + float alpha_d = (float) d[3] / 255.0f; + if (is_atop) d[3] = alpha_s; + alpha_s = alpha_s / 255.0f * o; + float alpha = alpha_s + alpha_d - alpha_s * alpha_d; + if (!is_atop) d[3] = 255 * alpha; + alpha = alpha_s / alpha; - //zdaj pa po x - p[0]=p1[3]; p[1]=p2[3]; p[2]=p3[3]; p[3]=p4[3]; - for (j=1;j<4;j++) - for (i=3;i>=j;i--) - p[i]=p[i]+(x-i-m)/j*(p[i]-p[i-1]); + a = s[k]+(s[k1]-s[k])*(x-(float)m); + b = s[l]+(s[l1]-s[n1])*(x-(float)m); + d[0] = d[0] * (1.0f - alpha) + (a+(b-a)*(y-(float)n)) * alpha; - if (p[3]<0.0) p[3]=0.0; //printf("p=%f ",p[3]); - if (p[3]>256.0) p[3]=255.0; //printf("p=%f ",p[3]); + a = s[k+1]+(s[k1+1]-s[k+1])*(x-(float)m); + b = s[l+1]+(s[l1+1]-s[n1+1])*(x-(float)m); + d[1] = d[1] * (1.0f - alpha) + (a+(b-a)*(y-(float)n)) * alpha; - *v=p[3]; + a = s[k+2]+(s[k1+2]-s[k+2])*(x-(float)m); + b = s[l+2]+(s[l1+2]-s[n1+2])*(x-(float)m); + d[2] = d[2] * (1.0f - alpha) + (a+(b-a)*(y-(float)n)) * alpha; return 0; } -//------------------------------------------------------ -//bikubicna interpolacija "smooth" -//za byte (char) vrednosti v packed color 32 bitnem formatu -int interpBC_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) +// bicubic + +int interpBC_b32(unsigned char *s, int w, int h, float x, float y, float o, unsigned char *d, int is_atop) { int i,j,b,l,m,n; float k; @@ -272,535 +118,50 @@ if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; #endif - m=(int)ceilf(x)-2; if (m<0) m=0; if ((m+5)>w) m=w-4; - n=(int)ceilf(y)-2; if (n<0) n=0; if ((n+5)>h) n=h-4; + m = (int)ceilf(x)-2; if (m<0) m=0; if ((m+5)>w) m=w-4; + n = (int)ceilf(y)-2; if (n<0) n=0; if ((n+5)>h) n=h-4; - for (b=3;b>-1;b--) + for (b = 3; b >- 1; b--) { - //njaprej po y (stiri stolpce) - for (i=0;i<4;i++) + // first after y (four columns) + for (i = 0; i < 4; i++) { - l=m+(i+n)*w; - p1[i]=sl[4*l+b]; - p2[i]=sl[4*(l+1)+b]; - p3[i]=sl[4*(l+2)+b]; - p4[i]=sl[4*(l+3)+b]; + l = m+(i+n)*w; + p1[i] = s[4*l+b]; + p2[i] = s[4*(l+1)+b]; + p3[i] = s[4*(l+2)+b]; + p4[i] = s[4*(l+3)+b]; } - for (j=1;j<4;j++) - for (i=3;i>=j;i--) + for (j = 1; j < 4; j++) + for (i = 3; i >= j; i--) { - k=(y-i-n)/j; - p1[i]=p1[i]+k*(p1[i]-p1[i-1]); - p2[i]=p2[i]+k*(p2[i]-p2[i-1]); - p3[i]=p3[i]+k*(p3[i]-p3[i-1]); - p4[i]=p4[i]+k*(p4[i]-p4[i-1]); + k = (y-i-n)/j; + p1[i] = p1[i]+k*(p1[i]-p1[i-1]); + p2[i] = p2[i]+k*(p2[i]-p2[i-1]); + p3[i] = p3[i]+k*(p3[i]-p3[i-1]); + p4[i] = p4[i]+k*(p4[i]-p4[i-1]); } - //zdaj pa po x - p[0]=p1[3]; p[1]=p2[3]; p[2]=p3[3]; p[3]=p4[3]; - for (j=1;j<4;j++) - for (i=3;i>=j;i--) - p[i]=p[i]+(x-i-m)/j*(p[i]-p[i-1]); + // now after x + p[0] = p1[3]; p[1] = p2[3]; p[2] = p3[3]; p[3] = p4[3]; + for (j = 1; j < 4; j++) + for (i = 3; i >= j; i--) + p[i] = p[i]+(x-i-m)/j*(p[i]-p[i-1]); if (p[3] < 0.0f) p[3] = 0.0f; if (p[3] > 255.0f) p[3] = 255.0f; if (b == 3) { - float alpha_sl = (float) p[3] / 255.0f * o; - float alpha_v = (float) v[3] / 255.0f; - alpha = alpha_sl + alpha_v - alpha_sl * alpha_v; - v[3] = is_atop? p[3] : (255 * alpha); - alpha = alpha_sl / alpha; + float alpha_s = (float) p[3] / 255.0f * o; + float alpha_d = (float) d[3] / 255.0f; + alpha = alpha_s + alpha_d - alpha_s * alpha_d; + d[3] = is_atop? p[3] : (255 * alpha); + alpha = alpha_s / alpha; } else { - v[b] = v[b] * (1.0f - alpha) + p[3] * alpha; + d[b] = d[b] * (1.0f - alpha) + p[3] * alpha; } } return 0; -} - -//------------------------------------------------------ -//bikubicna interpolacija "sharp" -//za byte (char) vrednosti -//Helmut Dersch polinom -// *sl vhodni array (slika) -// w,h dimenzija slike je wxh -// x,y tocka, za katero izracuna interpolirano vrednost -// o opacity -// *v interpolirana vrednost -//!!! ODKOD SUM??? (ze po eni rotaciji v interp_test !!) -//!!! v defish tega suma ni??? -int interpBC2_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) -{ - int i,k,l,m,n; - float pp,p[4],wx[4],wy[4],xx; - -#ifdef TEST_XY_LIMITS - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; -#endif - - m=(int)ceilf(x)-2; if (m<0) m=0; if ((m+5)>w) m=w-4; - n=(int)ceilf(y)-2; if (n<0) n=0; if ((n+5)>h) n=h-4; - - - //najprej po y (stiri stolpce) - xx=y-n; wy[0]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; - xx=xx-1.0; wy[1]=(1.25*xx-2.25)*xx*xx+1.0; - xx=1.0-xx; wy[2]=(1.25*xx-2.25)*xx*xx+1.0; - xx=xx+1.0; wy[3]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; - //se po x - xx=x-m; wx[0]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; - xx=xx-1.0; wx[1]=(1.25*xx-2.25)*xx*xx+1.0; - xx=1.0-xx; wx[2]=(1.25*xx-2.25)*xx*xx+1.0; - xx=xx+1.0; wx[3]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; - - k=n*w+m; - for (i=0;i<4;i++) - { - p[i]=0.0; - l=k+i; - p[i]=wy[0]*sl[l]; l+=w; - p[i]+=wy[1]*sl[l]; l+=w; - p[i]+=wy[2]*sl[l]; l+=w; - p[i]+=wy[3]*sl[l]; - } - - pp=wx[0]*p[0]; - pp+=wx[1]*p[1]; - pp+=wx[2]*p[2]; - pp+=wx[3]*p[3]; - - if (pp<0.0) pp=0.0; - if (pp>256.0) pp=255.0; - - *v=pp; - return 0; -} - -//------------------------------------------------------ -//bikubicna interpolacija "sharp" -//za byte (char) vrednosti v packed color 32 bitnem formatu -//!!! ODKOD SUM??? (ze po eni rotaciji v interp_test !!) -//!!! v defish tega suma ni??? -int interpBC2_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) -{ - int b,i,k,l,m,n,u; - float pp,p[4],wx[4],wy[4],xx; - -#ifdef TEST_XY_LIMITS - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; -#endif - - m=(int)ceilf(x)-2; if (m<0) m=0; if ((m+5)>w) m=w-4; - n=(int)ceilf(y)-2; if (n<0) n=0; if ((n+5)>h) n=h-4; - - //najprej po y (stiri stolpce) - xx=y-n; wy[0]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; - xx=xx-1.0; wy[1]=(1.25*xx-2.25)*xx*xx+1.0; - xx=1.0-xx; wy[2]=(1.25*xx-2.25)*xx*xx+1.0; - xx=xx+1.0; wy[3]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; - //se po x - xx=x-m; wx[0]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; - xx=xx-1.0; wx[1]=(1.25*xx-2.25)*xx*xx+1.0; - xx=1.0-xx; wx[2]=(1.25*xx-2.25)*xx*xx+1.0; - xx=xx+1.0; wx[3]=(-0.75*(xx-5.0)*xx-6.0)*xx+3.0; - - k=4*(n*w+m); u=4*w; - for (b=0;b<4;b++) - { - for (i=0;i<4;i++) - { - p[i]=0.0; - l=k+4*i; - p[i]=wy[0]*sl[l]; l+=u; - p[i]+=wy[1]*sl[l]; l+=u; - p[i]+=wy[2]*sl[l]; l+=u; - p[i]+=wy[3]*sl[l]; - } - k++; - - pp=wx[0]*p[0]; - pp+=wx[1]*p[1]; - pp+=wx[2]*p[2]; - pp+=wx[3]*p[3]; - - if (pp<0.0) pp=0.0; - if (pp>256.0) pp=255.0; - - v[b]=pp; - } - - return 0; -} - -//------------------------------------------------------ -//spline 4x4 interpolacija -//za byte (char) vrednosti -//Helmut Dersch polinom -// *sl vhodni array (slika) -// w,h dimenzija slike je wxh -// x,y tocka, za katero izracuna interpolirano vrednost -// o opacity -// *v interpolirana vrednost -int interpSP4_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) -{ - int i,j,m,n; - float pp,p[4],wx[4],wy[4],xx; - -#ifdef TEST_XY_LIMITS - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; -#endif - - m=(int)ceilf(x)-2; if (m<0) m=0; if ((m+5)>w) m=w-4; - n=(int)ceilf(y)-2; if (n<0) n=0; if ((n+5)>h) n=h-4; - - //najprej po y (stiri stolpce) - xx=y-n; wy[0]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); - xx=xx-1.0; wy[1]=((xx-1.8)*xx-0.2)*xx+1.0; - xx=1.0-xx; wy[2]=((xx-1.8)*xx-0.2)*xx+1.0; - xx=xx+1.0; wy[3]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); - //se po x - xx=x-m; wx[0]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); - xx=xx-1.0; wx[1]=((xx-1.8)*xx-0.2)*xx+1.0; - xx=1.0-xx; wx[2]=((xx-1.8)*xx-0.2)*xx+1.0; - xx=xx+1.0; wx[3]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); - - for (i=0;i<4;i++) - { - p[i]=0.0; - for (j=0;j<4;j++) - { - p[i]=p[i]+wy[j]*sl[(j+n)*w+i+m]; - } - } - - pp=0.0; - for (i=0;i<4;i++) - pp=pp+wx[i]*p[i]; - - if (pp<0.0) pp=0.0; - if (pp>256.0) pp=255.0; - - *v=pp; - return 0; -} - -//------------------------------------------------------ -//spline 4x4 interpolacija -//za byte (char) vrednosti v packed color 32 bitnem formatu -int interpSP4_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) -{ - int i,j,m,n,b; - float pp,p[4],wx[4],wy[4],xx; - -#ifdef TEST_XY_LIMITS - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; -#endif - - m=(int)ceilf(x)-2; if (m<0) m=0; if ((m+5)>w) m=w-4; - n=(int)ceilf(y)-2; if (n<0) n=0; if ((n+5)>h) n=h-4; - - //najprej po y (stiri stolpce) - xx=y-n; wy[0]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); - xx=xx-1.0; wy[1]=((xx-1.8)*xx-0.2)*xx+1.0; - xx=1.0-xx; wy[2]=((xx-1.8)*xx-0.2)*xx+1.0; - xx=xx+1.0; wy[3]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); - //se po x - xx=x-m; wx[0]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); - xx=xx-1.0; wx[1]=((xx-1.8)*xx-0.2)*xx+1.0; - xx=1.0-xx; wx[2]=((xx-1.8)*xx-0.2)*xx+1.0; - xx=xx+1.0; wx[3]=((-0.333333*(xx-1.0)+0.8)*(xx-1.0)-0.466667)*(xx-1.0); - - for (b=0;b<4;b++) - { - for (i=0;i<4;i++) - { - p[i]=0.0; - for (j=0;j<4;j++) - { - p[i]=p[i]+wy[j]*sl[4*((j+n)*w+i+m)+b]; - } - } - - pp=0.0; - for (i=0;i<4;i++) - pp=pp+wx[i]*p[i]; - - if (pp<0.0) pp=0.0; - if (pp>256.0) pp=255.0; - - v[b]=pp; - } - - return 0; -} - -//------------------------------------------------------ -//spline 6x6 interpolacija -//za byte (char) vrednosti -//Helmut Dersch polinom -// *sl vhodni array (slika) -// w,h dimenzija slike je wxh -// x,y tocka, za katero izracuna interpolirano vrednost -// o opacity -// *v interpolirana vrednost -//!!! PAZI, TOLE NE DELA CISTO PRAV ??? belina se siri -//!!! zaenkrat sem dodal fudge factor... -int interpSP6_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) -{ - int i,j,m,n; - float pp,p[6],wx[6],wy[6],xx; - -#ifdef TEST_XY_LIMITS - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; -#endif - - m=(int)ceilf(x)-3; if (m<0) m=0; if ((m+7)>w) m=w-6; - n=(int)ceilf(y)-3; if (n<0) n=0; if ((n+7)>h) n=h-6; - - //najprej po y (sest stolpcev) - xx=y-n; - wy[0]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); - xx=xx-1.0; - wy[1]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); - xx=xx-1.0; - wy[2]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; - xx=1.0-xx; - wy[3]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; - xx=xx+1.0; - wy[4]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); - xx=xx+1.0; - wy[5]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); - //se po x - xx=x-m; - wx[0]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); - xx=xx-1.0; - wx[1]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); - xx=xx-1.0; - wx[2]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; - xx=1.0-xx; - wx[3]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; - xx=xx+1.0; - wx[4]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); - xx=xx+1.0; - wx[5]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); - - - for (i=0;i<6;i++) - { - p[i]=0.0; - for (j=0;j<6;j++) - { - p[i]=p[i]+wy[j]*sl[(j+n)*w+i+m]; - } - } - - pp=0.0; - for (i=0;i<6;i++) - pp=pp+wx[i]*p[i]; - - pp=0.947*pp; //fudge factor...!!! cca 0.947... - if (pp<0.0) pp=0.0; - if (pp>256.0) pp=255.0; - - *v=pp; - return 0; -} - -//------------------------------------------------------ -//spline 6x6 interpolacija -//za byte (char) vrednosti v packed color 32 bitnem formatu -//!!! PAZI, TOLE NE DELA CISTO PRAV ??? belina se siri -//!!! zaenkrat sem dodal fudge factor... -int interpSP6_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) -{ - int i,b,j,m,n; - float pp,p[6],wx[6],wy[6],xx; - -#ifdef TEST_XY_LIMITS - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; -#endif - - m=(int)ceilf(x)-3; if (m<0) m=0; if ((m+7)>w) m=w-6; - n=(int)ceilf(y)-3; if (n<0) n=0; if ((n+7)>h) n=h-6; - - //najprej po y (sest stolpcev) - xx=y-n; - wy[0]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); - xx=xx-1.0; - wy[1]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); - xx=xx-1.0; - wy[2]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; - xx=1.0-xx; - wy[3]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; - xx=xx+1.0; - wy[4]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); - xx=xx+1.0; - wy[5]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); - //se po x - xx=x-m; - wx[0]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); - xx=xx-1.0; - wx[1]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); - xx=xx-1.0; - wx[2]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; - xx=1.0-xx; - wx[3]=((1.181818*xx-2.167464)*xx+0.014354)*xx+1.0; - xx=xx+1.0; - wx[4]=((-0.545455*(xx-1.0)+1.291866)*(xx-1.0)-0.746411)*(xx-1.0); - xx=xx+1.0; - wx[5]=((0.090909*(xx-2.0)-0.215311)*(xx-2.0)+0.124402)*(xx-2.0); - - - for (b=0;b<4;b++) - { - for (i=0;i<6;i++) - { - p[i]=0.0; - for (j=0;j<6;j++) - { - p[i]=p[i]+wy[j]*sl[4*((j+n)*w+i+m)+b]; - } - } - - pp=0.0; - for (i=0;i<6;i++) - pp=pp+wx[i]*p[i]; - - pp=0.947*pp; //fudge factor...!!! cca 0.947... - if (pp<0.0) pp=0.0; - if (pp>256.0) pp=255.0; - - v[b]=pp; - } - - return 0; -} - -//------------------------------------------------------ -//truncated sinc "lanczos" 16x16 interpolacija -//za byte (char) vrednosti -// *sl vhodni array (slika) -// w,h dimenzija slike je wxh -// x,y tocka, za katero izracuna interpolirano vrednost -// o opacity -// *v interpolirana vrednost -int interpSC16_b(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) -{ - int i,j,m,n; - float pp,p[16],wx[16],wy[16],xx,xxx,x1; - float PI=3.141592654; - -#ifdef TEST_XY_LIMITS - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; -#endif - - m=(int)ceilf(x)-8; if (m<0) m=0; if ((m+17)>w) m=w-16; - n=(int)ceilf(y)-8; if (n<0) n=0; if ((n+17)>h) n=h-16; - - //najprej po y - xx=y-n; - for (i=7;i>=0;i--) - { - x1=xx*PI; - wy[7-i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); - xxx=(float)(2*i+1)-xx; - x1=xxx*PI; - wy[8+i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); - xx=xx-1.0; - } - //se po x - xx=x-m; - for (i=7;i>=0;i--) - { - x1=xx*PI; - wx[7-i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); - xxx=(float)(2*i+1)-xx; - x1=xxx*PI; - wx[8+i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); - xx=xx-1.0; - } - - for (i=0;i<16;i++) - { - p[i]=0.0; - for (j=0;j<16;j++) - { - p[i]=p[i]+wy[j]*sl[(j+n)*w+i+m]; - } - } - - pp=0.0; - for (i=0;i<16;i++) - pp=pp+wx[i]*p[i]; - - if (pp<0.0) pp=0.0; - if (pp>256.0) pp=255.0; - - *v=pp; - return 0; -} - -//------------------------------------------------------ -//truncated sinc "lanczos" 16x16 interpolacija -//za byte (char) vrednosti v packed color 32 bitnem formatu -int interpSC16_b32(unsigned char *sl, int w, int h, float x, float y, float o, unsigned char *v, int is_atop) -{ - int i,j,m,b,n; - float pp,p[16],wx[16],wy[16],xx,xxx,x1; - float PI=3.141592654; - -#ifdef TEST_XY_LIMITS - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return -1; -#endif - - m=(int)ceilf(x)-8; if (m<0) m=0; if ((m+17)>w) m=w-16; - n=(int)ceilf(y)-8; if (n<0) n=0; if ((n+17)>h) n=h-16; - - //najprej po y - xx=y-n; - for (i=7;i>=0;i--) - { - x1=xx*PI; - wy[7-i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); - xxx=(float)(2*i+1)-xx; - x1=xxx*PI; - wy[8+i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); - xx=xx-1.0; - } - //se po x - xx=x-m; - for (i=7;i>=0;i--) - { - x1=xx*PI; - wx[7-i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); - xxx=(float)(2*i+1)-xx; - x1=xxx*PI; - wx[8+i]=(sin(x1)/(x1))*(sin(x1*0.125)/(x1*0.125)); - xx=xx-1.0; - } - - for (b=0;b<4;b++) - { - for (i=0;i<16;i++) - { - p[i]=0.0; - for (j=0;j<16;j++) - { - p[i]=p[i]+wy[j]*sl[4*((j+n)*w+i+m)+b]; - } - } - - pp=0.0; - for (i=0;i<16;i++) - pp=pp+wx[i]*p[i]; - - if (pp<0.0) pp=0.0; - if (pp>256.0) pp=255.0; - - v[b]=pp; - } - - return 0; } diff -Nru mlt-7.4.0/src/modules/plus/producer_pgm.c mlt-7.6.0/src/modules/plus/producer_pgm.c --- mlt-7.4.0/src/modules/plus/producer_pgm.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/producer_pgm.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,7 +1,6 @@ /* * producer_pgm.c -- PGM producer - * Copyright (C) 2005 Visual Media Fx Inc. - * Author: Charles Yates + * Copyright (C) 2008-2022 Meltytech, LLC * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by diff -Nru mlt-7.4.0/src/modules/plus/producer_pgm.yml mlt-7.6.0/src/modules/plus/producer_pgm.yml --- mlt-7.4.0/src/modules/plus/producer_pgm.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/producer_pgm.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,11 +1,18 @@ -schema_version: 0.1 +schema_version: 7.0 type: producer identifier: pgm title: PGM Image version: 1 -copyright: Visual Media FX ? creator: Charles Yates license: LGPLv2.1 language: en tags: - Video + +parameters: + - identifier: resource + argument: yes + type: string + title: File Name + required: yes + mutable: no diff -Nru mlt-7.4.0/src/modules/plus/transition_affine.c mlt-7.6.0/src/modules/plus/transition_affine.c --- mlt-7.4.0/src/modules/plus/transition_affine.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/transition_affine.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * transition_affine.c -- affine transformations - * Copyright (C) 2003-2021 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -327,13 +327,12 @@ { (void) id; // unused struct sliced_desc ctx = *((struct sliced_desc*) cookie); - int height_slice = (ctx.a_height + jobs / 2) / jobs; - int starty = height_slice * index; + int starty, height_slice = mlt_slices_size_slice(jobs, index, ctx.a_height, &starty); double x, y; double dx, dy; int i, j; - ctx.a_image += (index * height_slice) * (ctx.a_width * 4); + ctx.a_image += starty * (ctx.a_width * 4); for (i = 0, y = ctx.lower_y; i < ctx.a_height; i++, y++) { if (i >= starty && i < (starty + height_slice)) { for (j = 0, x = ctx.lower_x; j < ctx.a_width; j++, x++) { @@ -483,7 +482,7 @@ b_height = MAX(b_width * b_ar / b_dar, 1); } // Set the rescale interpolation to match the frame - mlt_properties_set( b_props, "rescale.interp", mlt_properties_get( a_props, "rescale.interp" ) ); + mlt_properties_set( b_props, "consumer.rescale", mlt_properties_get( a_props, "consumer.rescale" ) ); // Disable padding (resize filter) mlt_properties_set_int( b_props, "distort", 1 ); } else if (mlt_properties_get_int(b_props, "always_scale") || (!mlt_properties_get_int(b_props, "interpolation_not_required") @@ -496,7 +495,7 @@ b_height = MAX(b_width * b_ar / b_dar, 1); } // Set the rescale interpolation to match the frame - mlt_properties_set( b_props, "rescale.interp", mlt_properties_get( a_props, "rescale.interp" ) ); + mlt_properties_set( b_props, "consumer.rescale", mlt_properties_get( a_props, "consumer.rescale" ) ); // Disable padding (resize filter) mlt_properties_set_int( b_props, "distort", 1 ); } else { @@ -511,16 +510,16 @@ // Check if we are applied as a filter inside a transition if (b_resource && !strcmp("", b_resource)) { // Set the rescale interpolation to match the frame - mlt_properties_set( b_props, "rescale.interp", mlt_properties_get( a_props, "rescale.interp" ) ); + mlt_properties_set( b_props, "consumer.rescale", mlt_properties_get( a_props, "consumer.rescale" ) ); } else { // Suppress padding and aspect normalization. - mlt_properties_set( b_props, "rescale.interp", "none" ); + mlt_properties_set( b_props, "consumer.rescale", "none" ); } } mlt_log_debug(MLT_TRANSITION_SERVICE(transition), "requesting image B at resolution %dx%d\n", b_width, b_height); // This is not a field-aware transform. - mlt_properties_set_int( b_props, "consumer_deinterlace", 1 ); + mlt_properties_set_int( b_props, "consumer.progressive", 1 ); error = mlt_frame_get_image( b_frame, &b_image, &b_format, &b_width, &b_height, 0 ); if (error || !b_image) { @@ -623,7 +622,7 @@ } - char *interps = mlt_properties_get( a_props, "rescale.interp" ); + char *interps = mlt_properties_get( a_props, "consumer.rescale" ); // Copy in case string is changed. if ( interps ) interps = strdup( interps ); diff -Nru mlt-7.4.0/src/modules/plus/transition_affine.yml mlt-7.6.0/src/modules/plus/transition_affine.yml --- mlt-7.4.0/src/modules/plus/transition_affine.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plus/transition_affine.yml 2022-04-19 08:45:42.000000000 +0000 @@ -79,6 +79,7 @@ minimum: 0 default: 0 mutable: yes + animation: yes unit: pixels - identifier: oy @@ -87,6 +88,7 @@ minimum: 0 default: 0 mutable: yes + animation: yes unit: pixels - identifier: rotate_x @@ -126,6 +128,7 @@ unit: degrees default: 0 mutable: yes + animation: yes - identifier: fix_rotate_y title: Y axis rotation @@ -134,6 +137,7 @@ unit: degrees default: 0 mutable: yes + animation: yes - identifier: fix_rotate_z title: Z axis rotation @@ -142,6 +146,7 @@ unit: degrees default: 0 mutable: yes + animation: yes - identifier: shear_x title: Shear along X axis @@ -180,6 +185,7 @@ unit: degrees default: 0 mutable: yes + animation: yes - identifier: fix_shear_y title: Y axis shear @@ -188,6 +194,7 @@ unit: degrees default: 0 mutable: yes + animation: yes - identifier: fix_shear_z title: Z axis shear @@ -196,6 +203,7 @@ unit: degrees default: 0 mutable: yes + animation: yes - identifier: mirror title: Ping-pong @@ -222,6 +230,7 @@ type: float default: 0 mutable: yes + animation: yes - identifier: scale_y title: Vertical scale @@ -229,6 +238,7 @@ type: float default: 0 mutable: yes + animation: yes - identifier: invert_scale title: Invert Scale @@ -310,6 +320,7 @@ default: "0%/0%:100%x100%:100%" readonly: no mutable: yes + animation: yes - identifier: b_scaled title: Do not use full resolution of B frame diff -Nru mlt-7.4.0/src/modules/plusgpl/factory.c mlt-7.6.0/src/modules/plusgpl/factory.c --- mlt-7.4.0/src/modules/plusgpl/factory.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plusgpl/factory.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * factory.c -- the factory method interfaces - * Copyright (C) 2008-2014 Dan Dennedy + * Copyright (C) 2008-2022 Dan Dennedy * * 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 @@ -48,4 +48,5 @@ MLT_REGISTER_METADATA( mlt_service_filter_type, "burningtv", metadata, "filter_burningtv.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "lumaliftgaingamma", metadata, "filter_lumaliftgaingamma.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "rotoscoping", metadata, "filter_rotoscoping.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "telecide", metadata, "filter_telecide.yml" ); } diff -Nru mlt-7.4.0/src/modules/plusgpl/filter_burningtv.yml mlt-7.6.0/src/modules/plusgpl/filter_burningtv.yml --- mlt-7.4.0/src/modules/plusgpl/filter_burningtv.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plusgpl/filter_burningtv.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: burningtv title: BurningTV @@ -11,3 +11,22 @@ language: en tags: - Video + +parameters: + - identifier: foreground + title: Foreground + description: > + Whether to separate the background and burn only the foreground. The + background is based upon the first frame received by the filter. + type: boolean + default: 0 + mutable: yes + + - identifier: threshold + title: Movement Threshold + type: integer + minimum: 0 + maximum: 255 + default: 50 + mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/plusgpl/filter_lumaliftgaingamma.yml mlt-7.6.0/src/modules/plusgpl/filter_lumaliftgaingamma.yml --- mlt-7.4.0/src/modules/plusgpl/filter_lumaliftgaingamma.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/plusgpl/filter_lumaliftgaingamma.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: lumaliftgaingamma title: LumaLiftGainGamma @@ -23,6 +23,8 @@ description: > Adds a value computed using parameter value to color channel values. + mutable: yes + animation: yes - identifier: gain title: Gain @@ -33,6 +35,8 @@ description: > Multiplies color channel values by value computed using parameter value. + mutable: yes + animation: yes - identifier: gamma title: Gamma @@ -43,3 +47,5 @@ description: > Applies a gamma correction to all color channel values. + mutable: yes + animation: yes diff -Nru mlt-7.4.0/src/modules/plusgpl/filter_telecide.yml mlt-7.6.0/src/modules/plusgpl/filter_telecide.yml --- mlt-7.4.0/src/modules/plusgpl/filter_telecide.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/plusgpl/filter_telecide.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,18 @@ +schema_version: 7.0 +type: filter +identifier: telecide +title: Inverse Telecine (*DEPRECATED*) +version: 1 +copyright: Donald A. Graft and Dan Dennedy +creator: Donald A. Graft +contributor: + - Dan Dennedy +license: GPLv2 +language: en +tags: + - Video +description: Deinterlace frames that were repeated in a telecine process. +notes: > + This is old work, which never materialized to a completely usable form. It + is not able to change the frame rate. The video is deinterlaced in a smart + manner, but repeated frames are not removed. diff -Nru mlt-7.4.0/src/modules/qt/CMakeLists.txt mlt-7.6.0/src/modules/qt/CMakeLists.txt --- mlt-7.4.0/src/modules/qt/CMakeLists.txt 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/CMakeLists.txt 2022-04-19 08:45:42.000000000 +0000 @@ -7,6 +7,7 @@ common.cpp graph.cpp qimage_wrapper.cpp kdenlivetitle_wrapper.cpp + filter_audiolevelgraph.cpp filter_audiowaveform.cpp filter_qtext.cpp filter_qtblend.cpp @@ -61,6 +62,8 @@ install(TARGETS mltqt LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES + filter_audiolevelgraph.yml + filter_audiospectrum.yml filter_audiowaveform.yml filter_qtblend.yml filter_qtcrop.yml diff -Nru mlt-7.4.0/src/modules/qt/consumer_qglsl.yml mlt-7.6.0/src/modules/qt/consumer_qglsl.yml --- mlt-7.4.0/src/modules/qt/consumer_qglsl.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/consumer_qglsl.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,15 @@ +schema_version: 7.0 +type: consumer +identifier: qglsl +title: Qt OpenGL Context +version: 1 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +tags: + - Video +description: > + Creates an OpenGL context using Qt to use with the movit module in terminal + (melt) or headless (xvfb) situations. This is based on the "multi" consumer; + so, see its documentation. + diff -Nru mlt-7.4.0/src/modules/qt/factory.c mlt-7.6.0/src/modules/qt/factory.c --- mlt-7.4.0/src/modules/qt/factory.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/factory.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,7 +1,5 @@ /* - * factory.c -- the factory method interfaces - * Copyright (C) 2006 Visual Media - * Author: Charles Yates + * Copyright (C) 2008-2022 Meltytech, LLC * * 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 @@ -25,6 +23,7 @@ #ifdef USE_QT_OPENGL extern mlt_consumer consumer_qglsl_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); #endif +extern mlt_filter filter_audiolevelgraph_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_audiowaveform_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_qtext_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_qimage_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); @@ -53,6 +52,7 @@ #ifdef USE_QT_OPENGL MLT_REGISTER( mlt_service_consumer_type, "qglsl", consumer_qglsl_init ); #endif + MLT_REGISTER( mlt_service_filter_type, "audiolevelgraph", filter_audiolevelgraph_init ); MLT_REGISTER( mlt_service_filter_type, "audiowaveform", filter_audiowaveform_init ); MLT_REGISTER( mlt_service_filter_type, "qtext", filter_qtext_init ); MLT_REGISTER( mlt_service_producer_type, "qimage", producer_qimage_init ); @@ -62,6 +62,7 @@ MLT_REGISTER( mlt_service_filter_type, "qtblend", filter_qtblend_init ); MLT_REGISTER( mlt_service_filter_type, "qtcrop", filter_qtcrop_init ); MLT_REGISTER( mlt_service_filter_type, "typewriter", filter_typewriter_init ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "qglsl", metadata, "consumer_qglsl.yml" ); MLT_REGISTER_METADATA( mlt_service_transition_type, "qtblend", metadata, "transition_qtblend.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "qtblend", metadata, "filter_qtblend.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "qtcrop", metadata, "filter_qtcrop.yml" ); @@ -69,6 +70,7 @@ MLT_REGISTER( mlt_service_filter_type, "audiospectrum", filter_audiospectrum_init ); MLT_REGISTER( mlt_service_filter_type, "lightshow", filter_lightshow_init ); #endif + MLT_REGISTER_METADATA( mlt_service_filter_type, "audiolevelgraph", metadata, "filter_audiolevelgraph.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "audiowaveform", metadata, "filter_audiowaveform.yml" ); MLT_REGISTER_METADATA( mlt_service_filter_type, "qtext", metadata, "filter_qtext.yml" ); #ifdef USE_FFTW diff -Nru mlt-7.4.0/src/modules/qt/filter_audiolevelgraph.cpp mlt-7.6.0/src/modules/qt/filter_audiolevelgraph.cpp --- mlt-7.4.0/src/modules/qt/filter_audiolevelgraph.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/filter_audiolevelgraph.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,308 @@ +/* + * filter_audiolevel.cpp -- audio level visualization filter + * Copyright (c) 2021-2022 Meltytech, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "common.h" +#include "graph.h" +#include +#include +#include // memset +#include +#include +#include +#include //pow + +// Private Types +typedef struct +{ + mlt_filter levels_filter; + int preprocess_warned; +} private_data; + +static int filter_get_audio( mlt_frame frame, void** buffer, mlt_audio_format* format, int* frequency, int* channels, int* samples ) +{ + mlt_filter filter = (mlt_filter)mlt_frame_pop_audio( frame ); + mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); + private_data* pdata = (private_data*)filter->child; + + // Create the audiolevel filter the first time. + if( !pdata->levels_filter ) + { + mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) ); + pdata->levels_filter = mlt_factory_filter( profile, "audiolevel", NULL ); + if( !pdata->levels_filter ) + { + mlt_log_warning( MLT_FILTER_SERVICE(filter), "Unable to create audiolevel filter.\n" ); + return 1; + } + } + + // The service must stay locked while using the private data + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); + + // Perform audio level processing on the frame + mlt_filter_process( pdata->levels_filter, frame ); + mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); + + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); + + return 0; +} + +double get_level_from_frame( mlt_frame frame, int channel ) +{ + char prop_str[30]; + snprintf ( prop_str, 30, "meta.media.audio_level.%d", channel ); + return mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), prop_str); +} + +static void convert_levels( mlt_filter filter, mlt_frame frame, int channels, float* levels ) +{ + private_data* pdata = (private_data*)filter->child; + mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); + mlt_properties levels_properties = MLT_FILTER_PROPERTIES( pdata->levels_filter ); + mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); + int reverse = mlt_properties_get_int( filter_properties, "reverse" ); + int real_channels = mlt_properties_get_int( MLT_FRAME_PROPERTIES(frame), "audio_channels" ); + if (real_channels == 0) real_channels = 1; + + int chan_index = 0; + for( chan_index = 0; chan_index < channels; chan_index++ ) + { + double level = 0.0; + if ( channels == 1 ) + { + // For 1 channel display, average all channel levels + int real_chan_index = 0; + for ( real_chan_index = 0; real_chan_index < real_channels; real_chan_index ++ ) + { + level += get_level_from_frame( frame, real_chan_index ); + } + level /= real_channels; + } else { + int real_chan_index = chan_index % real_channels; + level = get_level_from_frame( frame, real_chan_index ); + } + + if( reverse ) + { + levels[channels - chan_index - 1] = level; + } else { + levels[chan_index] = level; + } + } +} + +static void draw_levels( mlt_filter filter, mlt_frame frame, QImage* qimg, int width, int height ) +{ + mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); + mlt_position position = mlt_filter_get_position( filter, frame ); + mlt_position length = mlt_filter_get_length2( filter, frame ); + mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter)); + mlt_rect rect = mlt_properties_anim_get_rect( filter_properties, "rect", position, length ); + if ( strchr( mlt_properties_get( filter_properties, "rect" ), '%' ) ) { + rect.x *= qimg->width(); + rect.w *= qimg->width(); + rect.y *= qimg->height(); + rect.h *= qimg->height(); + } + double scale = mlt_profile_scale_width(profile, width); + rect.x *= scale; + rect.w *= scale; + scale = mlt_profile_scale_height(profile, height); + rect.y *= scale; + rect.h *= scale; + char* graph_type = mlt_properties_get( filter_properties, "type" ); + int mirror = mlt_properties_get_int( filter_properties, "mirror" ); + int segments = mlt_properties_get_int( filter_properties, "segments" ); + int segment_gap = mlt_properties_get_int( filter_properties, "segment_gap" ) * scale; + int segment_width = mlt_properties_get_int( filter_properties, "thickness" ) * scale; + QVector colors = get_graph_colors( filter_properties ); + + QRectF r( rect.x, rect.y, rect.w, rect.h ); + QPainter p( qimg ); + + if( mirror ) { + // Draw two half rectangle instead of one full rectangle. + r.setHeight( r.height() / 2.0 ); + } + + setup_graph_painter( p, r, filter_properties ); + setup_graph_pen( p, r, filter_properties, scale ); + + int channels = mlt_properties_get_int( filter_properties, "channels" ); + if ( channels == 0 ) { + // "0" means use number of channels in the frame + channels = mlt_properties_get_int( MLT_FRAME_PROPERTIES(frame), "audio_channels" ); + } + if ( channels == 0 ) channels = 1; + float* levels = (float*)mlt_pool_alloc( channels * sizeof(float) ); + + convert_levels( filter, frame, channels, levels ); + + if( graph_type && graph_type[0] == 'b' ) { + paint_bar_graph( p, r, channels, levels ); + } else { + paint_segment_graph( p, r, channels, levels, colors, segments, segment_gap, segment_width ); + } + + if( mirror ) { + // Second rectangle is mirrored. + p.translate( 0, r.y() * 2 + r.height() * 2 ); + p.scale( 1, -1 ); + if( graph_type && graph_type[0] == 'b' ) { + paint_bar_graph( p, r, channels, levels ); + } else { + paint_segment_graph( p, r, channels, levels, colors, segments, segment_gap, segment_width ); + } + } + + mlt_pool_release( levels ); + + p.end(); +} +/** Get the image. +*/ +static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) +{ + int error = 0; + mlt_filter filter = (mlt_filter)mlt_frame_pop_service( frame ); + private_data* pdata = (private_data*)filter->child; + mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); + + if( mlt_properties_get( frame_properties, "meta.media.audio_level.0" ) ) + { + // Get the current image + *format = mlt_image_rgba; + error = mlt_frame_get_image( frame, image, format, width, height, 1 ); + + // Draw the audio levels + if( !error ) { + QImage qimg( *width, *height, QImage::Format_ARGB32 ); + convert_mlt_to_qimage_rgba( *image, &qimg, *width, *height ); + draw_levels( filter, frame, &qimg, *width, *height ); + convert_qimage_to_mlt_rgba( &qimg, *image, *width, *height ); + } + } else { + if ( pdata->preprocess_warned++ == 2 ) + { + // This filter depends on the consumer processing the audio before + // the video. + mlt_log_warning( MLT_FILTER_SERVICE(filter), "Audio not preprocessed.\n" ); + } + mlt_frame_get_image( frame, image, format, width, height, writable ); + } + + return error; +} + +/** Filter processing. +*/ +static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) +{ + if( mlt_frame_is_test_card( frame ) ) { + // The producer does not generate video. This filter will create an + // image on the producer's behalf. + mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); + mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) ); + mlt_properties_set_int( frame_properties, "progressive", 1 ); + mlt_properties_set_double( frame_properties, "aspect_ratio", mlt_profile_sar( profile ) ); + mlt_properties_set_int( frame_properties, "meta.media.width", profile->width ); + mlt_properties_set_int( frame_properties, "meta.media.height", profile->height ); + // Tell the framework that there really is an image. + mlt_properties_set_int( frame_properties, "test_image", 0 ); + // Push a callback to create the image. + mlt_frame_push_get_image( frame, create_image ); + } + + mlt_frame_push_audio( frame, filter ); + mlt_frame_push_audio( frame, (void*)filter_get_audio ); + mlt_frame_push_service( frame, filter ); + mlt_frame_push_get_image( frame, filter_get_image ); + return frame; +} + +static void filter_close( mlt_filter filter ) +{ + private_data* pdata = (private_data*)filter->child; + + if ( pdata ) + { + mlt_filter_close( pdata->levels_filter ); + free( pdata ); + } + filter->child = NULL; + filter->close = NULL; + filter->parent.close = NULL; + mlt_service_close( &filter->parent ); +} + +/** Constructor for the filter. +*/ + +extern "C" { + +mlt_filter filter_audiolevelgraph_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) +{ + mlt_filter filter = mlt_filter_new(); + private_data* pdata = (private_data*)calloc( 1, sizeof(private_data) ); + + if ( filter && pdata && createQApplicationIfNeeded( MLT_FILTER_SERVICE(filter) ) ) + { + mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); + mlt_properties_set_int( properties, "_filter_private", 1 ); + mlt_properties_set( properties, "type", "bar" ); + mlt_properties_set( properties, "bgcolor", "0x00000000" ); + mlt_properties_set( properties, "color.1", "0xffffffff" ); + mlt_properties_set( properties, "rect", "0% 0% 100% 100%" ); + mlt_properties_set( properties, "thickness", "0" ); + mlt_properties_set( properties, "fill", "0" ); + mlt_properties_set( properties, "mirror", "0" ); + mlt_properties_set( properties, "reverse", "0" ); + mlt_properties_set( properties, "angle", "0" ); + mlt_properties_set( properties, "gorient", "v" ); + mlt_properties_set_int( properties, "channels", 2 ); + mlt_properties_set_int( properties, "segment_gap", 10 ); + + pdata->levels_filter = 0; + + filter->close = filter_close; + filter->process = filter_process; + filter->child = pdata; + } + else + { + mlt_log_error( MLT_FILTER_SERVICE(filter), "Filter audio level graph failed\n" ); + + if( filter ) + { + mlt_filter_close( filter ); + } + + if( pdata ) + { + free( pdata ); + } + + filter = NULL; + } + return filter; +} + +} + diff -Nru mlt-7.4.0/src/modules/qt/filter_audiolevelgraph.yml mlt-7.6.0/src/modules/qt/filter_audiolevelgraph.yml --- mlt-7.4.0/src/modules/qt/filter_audiolevelgraph.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/filter_audiolevelgraph.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,168 @@ +schema_version: 0.3 +type: filter +identifier: audiolevelgraph +title: Audio Level Visualization Filter +version: 1 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +tags: + - Video +description: > + An audio visualization filter that draws an audio level meter on the image. + +parameters: + - identifier: type + title: Graph type + description: The type of graph to display the levels. + type: string + default: bar + values: + - segment + - bar + readonly: no + mutable: yes + widget: combo + + - identifier: bgcolor + title: Background Color + type: color + description: | + The background color to be applied to the entire frame. The default color + is transparent. + + A color value is a hexadecimal representation of RGB plus alpha channel + as 0xrrggbbaa. Colors can also be the words: white, black, red, green, + or blue. You can also use a HTML-style color values #rrggbb or #aarrggbb. + readonly: no + mutable: yes + widget: color + + - identifier: color.* + title: Foreground color + type: color + description: | + The color of the waveform. + + Multiple colors can be specified with incrementing suffixes to cause the + waveform to be drawn in a gradient. color.1 is the top of the waveform. + Subsequent colors will produce a gradient toward the bottom. + + By default, the filter has one color defined: + + color.1=0xffffffff" + + This results in a white waveform. + + To create a gradient, define more colors: + + color.2=green color.3=0x77777777 + + A color value is a hexadecimal representation of RGB plus alpha channel + as 0xrrggbbaa. Colors can also be the words: white, black, red, green, + or blue. You can also use a HTML-style color values #rrggbb or #aarrggbb. + readonly: no + mutable: yes + widget: color + + - identifier: thickness + title: Line Thickness + type: integer + description: > + The thickness of the bar or segments. + readonly: no + default: 0 + minimum: 0 + maximum: 20 + mutable: yes + widget: spinner + unit: pixels + + - identifier: angle + title: Angle + type: float + description: > + The rotation angle to be applied to the waveform. + readonly: no + default: 0 + minimum: 0 + maximum: 360 + mutable: yes + widget: spinner + + - identifier: rect + title: Rectangle + description: > + Defines the rectangle that the waveform(s) should be drawn in. + + Format is: "X Y W H". + + X, Y, W, H are assumed to be pixel units unless they have the suffix '%'. + type: rect + default: "0 0 100% 100%" + readonly: no + mutable: yes + + - identifier: mirror + title: Mirror + description: > + Mirror the spectrum about the center of the rectangle. + type: boolean + default: 0 + readonly: no + mutable: yes + widget: checkbox + + - identifier: reverse + title: Reverse + description: > + Draw the points starting with the right channel first. + type: boolean + default: 0 + readonly: no + mutable: yes + widget: checkbox + + - identifier: gorient + title: Gradient Orientation + description: Direction of the color gradient. + type: string + default: vertical + values: + - vertical + - horizontal + readonly: no + mutable: yes + widget: combo + + - identifier: channels + title: Channels + type: integer + description: > + The number of channels to show. + mutable: yes + readonly: no + default: 2 + + - identifier: segments + title: Segments + type: integer + description: > + The number of segments to draw if the graph type is "segment". + mutable: yes + readonly: no + default: 10 + minimum: 2 + maximum: 100 + + - identifier: segment_gap + title: Segment Gap + type: integer + description: > + The space in pixels between the segments. + mutable: yes + readonly: no + default: 10 + minimum: 0 + maximum: 100 + unit: pixels diff -Nru mlt-7.4.0/src/modules/qt/filter_audiospectrum.cpp mlt-7.6.0/src/modules/qt/filter_audiospectrum.cpp --- mlt-7.4.0/src/modules/qt/filter_audiospectrum.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/filter_audiospectrum.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_audiospectrum.cpp -- audio spectrum visualization filter - * Copyright (c) 2015-2020 Meltytech, LLC + * Copyright (c) 2015-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -199,6 +199,10 @@ int mirror = mlt_properties_get_int( filter_properties, "mirror" ); int fill = mlt_properties_get_int( filter_properties, "fill" ); double tension = mlt_properties_get_double( filter_properties, "tension" ); + int segments = mlt_properties_get_int( filter_properties, "segments" ); + int segment_gap = mlt_properties_get_int( filter_properties, "segment_gap" ) * scale; + int segment_width = mlt_properties_get_int( filter_properties, "thickness" ) * scale; + QVector colors = get_graph_colors( filter_properties ); QRectF r( rect.x, rect.y, rect.w, rect.h ); QPainter p( qimg ); @@ -222,6 +226,8 @@ if( graph_type && graph_type[0] == 'b' ) { paint_bar_graph( p, r, bands, spectrum ); + } else if ( graph_type && graph_type[0] == 's' ) { + paint_segment_graph( p, r, bands, spectrum, colors, segments, segment_gap, segment_width ); } else { paint_line_graph( p, r, bands, spectrum, tension, fill ); } @@ -233,6 +239,8 @@ if( graph_type && graph_type[0] == 'b' ) { paint_bar_graph( p, r, bands, spectrum ); + } else if ( graph_type && graph_type[0] == 's' ) { + paint_segment_graph( p, r, bands, spectrum, colors, segments, segment_gap, segment_width ); } else { paint_line_graph( p, r, bands, spectrum, tension, fill ); } @@ -346,6 +354,7 @@ mlt_properties_set( properties, "tension", "0.4" ); mlt_properties_set( properties, "angle", "0" ); mlt_properties_set( properties, "gorient", "v" ); + mlt_properties_set_int( properties, "segment_gap", 10 ); mlt_properties_set_int( properties, "bands", 31 ); mlt_properties_set_double( properties, "threshold", -60.0 ); mlt_properties_set_int( properties, "window_size", 8192 ); diff -Nru mlt-7.4.0/src/modules/qt/filter_audiospectrum.yml mlt-7.6.0/src/modules/qt/filter_audiospectrum.yml --- mlt-7.4.0/src/modules/qt/filter_audiospectrum.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/filter_audiospectrum.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: audiospectrum title: Audio Spectrum Filter @@ -103,7 +103,8 @@ default: "0 0 100% 100%" readonly: no mutable: yes - + animation: yes + - identifier: fill title: Fill description: > @@ -160,6 +161,18 @@ mutable: yes widget: combo + - identifier: segment_gap + title: Segment Gap + type: integer + description: > + The space in pixels between the segments. + mutable: yes + readonly: no + default: 10 + minimum: 0 + maximum: 100 + unit: pixels + - identifier: bands title: Points type: integer @@ -206,6 +219,17 @@ maximum: 0 unit: dB + - identifier: segments + title: Segments + type: integer + description: > + The number of segments to draw if the graph type is "segment". + mutable: yes + readonly: no + default: 10 + minimum: 2 + maximum: 100 + - identifier: window_size title: Window Size type: integer diff -Nru mlt-7.4.0/src/modules/qt/filter_audiowaveform.yml mlt-7.6.0/src/modules/qt/filter_audiowaveform.yml --- mlt-7.4.0/src/modules/qt/filter_audiowaveform.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/filter_audiowaveform.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: audiowaveform title: Audio Waveform Filter @@ -105,7 +105,8 @@ default: "0 0 100% 100%" readonly: no mutable: yes - + animation: yes + - identifier: fill title: Fill description: Whether the area under the waveform should be filled in. diff -Nru mlt-7.4.0/src/modules/qt/filter_lightshow.yml mlt-7.6.0/src/modules/qt/filter_lightshow.yml --- mlt-7.4.0/src/modules/qt/filter_lightshow.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/filter_lightshow.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: lightshow title: Light Show @@ -101,7 +101,8 @@ default: "0 0 100% 100%" readonly: no mutable: yes - + animation: yes + - identifier: window_size title: Window Size type: integer diff -Nru mlt-7.4.0/src/modules/qt/filter_qtblend.yml mlt-7.6.0/src/modules/qt/filter_qtblend.yml --- mlt-7.4.0/src/modules/qt/filter_qtblend.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/filter_qtblend.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: qtblend title: Composite and transform @@ -19,6 +19,7 @@ description: > Keyframable rectangle specification. mutable: yes + animation: yes - identifier: compositing title: Composition mode @@ -41,6 +42,7 @@ minimum: 0 maximum: 360 mutable: yes + animation: yes widget: spinner unit: degrees diff -Nru mlt-7.4.0/src/modules/qt/filter_qtcrop.yml mlt-7.6.0/src/modules/qt/filter_qtcrop.yml --- mlt-7.4.0/src/modules/qt/filter_qtcrop.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/filter_qtcrop.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: qtcrop title: Crop by padding @@ -21,6 +21,7 @@ argument: yes default: "0%/0%:100%x100%" mutable: yes + animation: yes - identifier: circle title: Use Circle @@ -37,6 +38,7 @@ minimum: 0.0 maximum: 1.0 mutable: yes + animation: yes - identifier: color title: Padding color diff -Nru mlt-7.4.0/src/modules/qt/filter_qtext.yml mlt-7.6.0/src/modules/qt/filter_qtext.yml --- mlt-7.4.0/src/modules/qt/filter_qtext.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/filter_qtext.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: qtext title: QText @@ -27,6 +27,8 @@ type: rect description: A set of X/Y coordinates by which to adjust the text. default: 0%/0%:100%x100%:100 + mutable: yes + animation: yes - identifier: family title: Font family diff -Nru mlt-7.4.0/src/modules/qt/graph.cpp mlt-7.6.0/src/modules/qt/graph.cpp --- mlt-7.4.0/src/modules/qt/graph.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/graph.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020 Meltytech, LLC + * Copyright (c) 2015-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,6 +21,30 @@ #include #include +QVector get_graph_colors( mlt_properties filter_properties ) +{ + QVector colors; + + // Find user specified colors for the gradient + while( true ) { + QString prop_name = QString("color.") + QString::number(colors.size() + 1); + if( mlt_properties_exists(filter_properties, prop_name.toUtf8().constData() ) ) { + mlt_color mcolor = mlt_properties_get_color( filter_properties, prop_name.toUtf8().constData() ); + colors.append( QColor( mcolor.r, mcolor.g, mcolor.b, mcolor.a ) ); + } else { + break; + } + } + + if( colors.size() == 0 ) + { + // No colors found - use a default. + colors.append( QColor( Qt::white ) ); + } + + return colors; +} + /* * Apply the "bgcolor" and "angle" parameters to the QPainter */ @@ -52,27 +76,11 @@ { int thickness = mlt_properties_get_int( filter_properties, "thickness" ) * scale; QString gorient = mlt_properties_get( filter_properties, "gorient" ); - QVector colors; - bool color_found = true; - + QVector colors = get_graph_colors( filter_properties ); QPen pen; pen.setWidth( qAbs(thickness) ); - // Find user specified colors for the gradient - while( color_found ) { - QString prop_name = QString("color.") + QString::number(colors.size() + 1); - if( mlt_properties_exists(filter_properties, prop_name.toUtf8().constData() ) ) { - mlt_color mcolor = mlt_properties_get_color( filter_properties, prop_name.toUtf8().constData() ); - colors.append( QColor( mcolor.r, mcolor.g, mcolor.b, mcolor.a ) ); - } else { - color_found = false; - } - } - - if( !colors.size() ) { - // No color specified. Just use white. - pen.setBrush(Qt::white); - } else if ( colors.size() == 1 ) { + if ( colors.size() == 1 ) { // Only use one color pen.setBrush(colors[0]); } else { @@ -192,3 +200,38 @@ topPoint.setX( bottomPoint.x() ); } } + +void paint_segment_graph( QPainter& p, const QRectF& rect, int points, const float* values, const QVector& colors, int segments, int segment_gap, int segment_width ) +{ + double pixelsPerPoint = rect.width() / (double)points; + if (segment_width > pixelsPerPoint) { + segment_width = pixelsPerPoint; + } + double segment_space = pixelsPerPoint - segment_width; + double segmentSize = rect.height() / (double)segments; + if ( segment_gap >= segmentSize ) { + segment_gap = segmentSize - 1; + } + segmentSize = (rect.height() - ((double)segment_gap * (double)(segments - 1))) / (double)segments; + for( int i = 0; i < points; i++ ) { + QPointF bottomPoint( rect.x() + (segment_space / 2.0) + (pixelsPerPoint * (double)i), rect.y() + rect.height() ); + QPointF topPoint( bottomPoint.x() + segment_width, bottomPoint.y() - segmentSize ); + qreal segmentRatio = 1.0 / (qreal)segments; + for (int s = 0; s < segments; s++ ) { + int colorIndex = colors.size() - qRound((qreal)s / (qreal) segments * (qreal)colors.size()) - 1; + colorIndex = qBound(0, colorIndex, colors.size()); + QColor segmentColor = colors[colorIndex]; + qreal minSegmentValue = segmentRatio * (qreal)s; + qreal maxSegmentValue = segmentRatio * (qreal)(s + 1); + if (values[i] < minSegmentValue) { + break; + } else if (values[i] < maxSegmentValue) { + qreal opacity = (values[i] - minSegmentValue) / segmentRatio; + segmentColor.setAlphaF(opacity); + } + p.fillRect(QRectF(topPoint, bottomPoint), segmentColor); + bottomPoint.setY( topPoint.y() - segment_gap ); + topPoint.setY( bottomPoint.y() - segmentSize ); + } + } +} diff -Nru mlt-7.4.0/src/modules/qt/graph.h mlt-7.6.0/src/modules/qt/graph.h --- mlt-7.4.0/src/modules/qt/graph.h 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/graph.h 2022-04-19 08:45:42.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020 Meltytech, LLC + * Copyright (c) 2015-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,13 +20,17 @@ #define GRAPH_H #include +#include #include #include +#include +QVector get_graph_colors( mlt_properties filter_properties ); void setup_graph_painter( QPainter& p, QRectF& rect, mlt_properties filter_properties ); void setup_graph_pen( QPainter& p, QRectF& rect, mlt_properties filter_properties, double scale ); void paint_line_graph( QPainter& p, QRectF& rect, int points, float* values, double tension, int fill ); void paint_bar_graph( QPainter& p, QRectF& rect, int points, float* values ); +void paint_segment_graph( QPainter& p, const QRectF& rect, int points, const float* values, const QVector& colors, int segments, int segment_gap, int segment_width ); #endif // GRAPH_H diff -Nru mlt-7.4.0/src/modules/qt/kdenlivetitle_wrapper.cpp mlt-7.6.0/src/modules/qt/kdenlivetitle_wrapper.cpp --- mlt-7.4.0/src/modules/qt/kdenlivetitle_wrapper.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/kdenlivetitle_wrapper.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -159,7 +159,6 @@ m_pen.setWidthF(outline); m_font = font; m_lineSpacing = lineSpacing + m_metrics.lineSpacing(); - m_path.setFillRule(Qt::WindingFill); m_align = align; m_width = width; updateText(text); @@ -189,6 +188,7 @@ } m_path.addPath(linePath); } + m_path.setFillRule(Qt::WindingFill); } virtual QRectF boundingRect() const @@ -207,7 +207,7 @@ painter->fillPath(m_path, m_brush); if ( m_outline > 0 ) { - painter->strokePath(m_path, m_pen); + painter->strokePath(m_path.simplified(), m_pen); } } diff -Nru mlt-7.4.0/src/modules/qt/producer_qimage.c mlt-7.6.0/src/modules/qt/producer_qimage.c --- mlt-7.4.0/src/modules/qt/producer_qimage.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/producer_qimage.c 2022-04-19 08:45:42.000000000 +0000 @@ -181,28 +181,6 @@ return result; } -static int load_folder( producer_qimage self, mlt_properties properties, const char *filename ) -{ - int result = 0; - - // Obtain filenames within folder - if ( strstr( filename, "/.all." ) != NULL ) - { - char wildcard[ 1024 ]; - char *dir_name = strdup( filename ); - char *extension = strrchr( dir_name, '.' ); - - *( strstr( dir_name, "/.all." ) + 1 ) = '\0'; - sprintf( wildcard, "*%s", extension ); - - mlt_properties_dir_list( self->filenames, dir_name, wildcard, 1 ); - - free( dir_name ); - result = 1; - } - return result; -} - static void load_filenames( producer_qimage self, mlt_properties properties ) { char *filename = mlt_properties_get( properties, "resource" ); @@ -212,7 +190,7 @@ !load_sequence_querystring( self, properties, filename ) && !load_sequence_sprintf( self, properties, filename ) && !load_sequence_deprecated( self, properties, filename ) && - !load_folder( self, properties, filename ) ) + !load_folder( self, filename ) ) { mlt_properties_set( self->filenames, "0", filename ); } diff -Nru mlt-7.4.0/src/modules/qt/producer_qimage.yml mlt-7.6.0/src/modules/qt/producer_qimage.yml --- mlt-7.4.0/src/modules/qt/producer_qimage.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/producer_qimage.yml 2022-04-19 08:45:42.000000000 +0000 @@ -3,7 +3,6 @@ identifier: qimage title: Qt QImage version: 2 -copyright: Visual Media ? creator: Charles Yates license: GPLv2 language: en diff -Nru mlt-7.4.0/src/modules/qt/qimage_wrapper.cpp mlt-7.6.0/src/modules/qt/qimage_wrapper.cpp --- mlt-7.4.0/src/modules/qt/qimage_wrapper.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/qimage_wrapper.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -26,6 +26,8 @@ #include #include +#include +#include #include #include #include @@ -245,7 +247,7 @@ // If we have a qimage and need a new scaled image if ( self->qimage && ( !self->current_image || ( format != mlt_image_none && format != mlt_image_movit && format != self->format ) ) ) { - QString interps = mlt_properties_get( properties, "rescale.interp" ); + QString interps = mlt_properties_get( properties, "consumer.rescale" ); bool interp = ( interps != "nearest" ) && ( interps != "none" ); QImage *qimage = static_cast( self->qimage ); int has_alpha = qimage->hasAlphaChannel(); @@ -458,4 +460,26 @@ return result; } +int load_folder( producer_qimage self, const char *filename ) +{ + int result = 0; + + // Obtain filenames within folder + if ( strstr( filename, "/.all." ) != NULL ) + { + mlt_properties filename_property = self->filenames; + QFileInfo info( filename ); + QDir dir = info.absoluteDir(); + QStringList filters = {QString( "*.%1" ).arg( info.suffix() )}; + QStringList files = dir.entryList( filters, QDir::Files, QDir::Name ); + int key; + for ( auto &f : files ) { + key = mlt_properties_count( filename_property ); + mlt_properties_set_string( filename_property, QString::number( key ).toLatin1(), dir.absoluteFilePath( f ).toUtf8().constData() ); + } + result = 1; + } + return result; +} + } // extern "C" diff -Nru mlt-7.4.0/src/modules/qt/qimage_wrapper.h mlt-7.6.0/src/modules/qt/qimage_wrapper.h --- mlt-7.4.0/src/modules/qt/qimage_wrapper.h 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/qimage_wrapper.h 2022-04-19 08:45:42.000000000 +0000 @@ -54,6 +54,7 @@ extern void make_tempfile( producer_qimage, const char *xml ); extern int init_qimage(mlt_producer producer, const char *filename); extern int load_sequence_sprintf( producer_qimage self, mlt_properties properties, const char *filename ); +extern int load_folder( producer_qimage self, const char *filename ); #ifdef __cplusplus diff -Nru mlt-7.4.0/src/modules/qt/transition_qtblend.cpp mlt-7.6.0/src/modules/qt/transition_qtblend.cpp --- mlt-7.4.0/src/modules/qt/transition_qtblend.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/qt/transition_qtblend.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -115,10 +115,10 @@ } // This is not a field-aware transform. - mlt_properties_set_int( b_properties, "consumer_deinterlace", 1 ); + mlt_properties_set_int( b_properties, "consumer.progressive", 1 ); // Suppress padding and aspect normalization. - char *interps = mlt_properties_get( properties, "rescale.interp" ); + char *interps = mlt_properties_get( properties, "consumer.rescale" ); if ( interps ) interps = strdup( interps ); diff -Nru mlt-7.4.0/src/modules/resample/filter_resample.yml mlt-7.6.0/src/modules/resample/filter_resample.yml --- mlt-7.4.0/src/modules/resample/filter_resample.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/resample/filter_resample.yml 2022-04-19 08:45:42.000000000 +0000 @@ -21,7 +21,7 @@ Assumes 2 channels during libsamplerate initialisation. Untested with >2 channels. parameters: - - identifier: argument + - identifier: requested title: Frequency type: integer description: The target sample rate. diff -Nru mlt-7.4.0/src/modules/rtaudio/consumer_rtaudio.cpp mlt-7.6.0/src/modules/rtaudio/consumer_rtaudio.cpp --- mlt-7.4.0/src/modules/rtaudio/consumer_rtaudio.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/rtaudio/consumer_rtaudio.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -279,7 +279,7 @@ // Default scaler (for now we'll use nearest) mlt_properties_set( properties, "rescale", "nearest" ); - mlt_properties_set( properties, "deinterlace_method", "onefield" ); + mlt_properties_set( properties, "consumer.deinterlacer", "onefield" ); // Default buffer for low latency mlt_properties_set_int( properties, "buffer", 1 ); diff -Nru mlt-7.4.0/src/modules/rubberband/filter_rbpitch.yml mlt-7.6.0/src/modules/rubberband/filter_rbpitch.yml --- mlt-7.4.0/src/modules/rubberband/filter_rbpitch.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/rubberband/filter_rbpitch.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.3 +schema_version: 7.0 type: filter identifier: rbpitch title: Rubberband Pitch @@ -23,6 +23,7 @@ Ignored if pitchscale is set. readonly: no mutable: yes + animation: yes default: 0.0 minimum: -3.3 maximum: 3.3 @@ -42,6 +43,7 @@ Overrides octaveshift. readonly: no mutable: yes + animation: yes default: 1.0 minimum: 0.1 maximum: 10 diff -Nru mlt-7.4.0/src/modules/sdl/consumer_sdl_audio.c mlt-7.6.0/src/modules/sdl/consumer_sdl_audio.c --- mlt-7.4.0/src/modules/sdl/consumer_sdl_audio.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/sdl/consumer_sdl_audio.c 2022-04-19 08:45:42.000000000 +0000 @@ -107,7 +107,7 @@ // Default scaler (for now we'll use nearest) mlt_properties_set( self->properties, "rescale", "nearest" ); - mlt_properties_set( self->properties, "deinterlace_method", "onefield" ); + mlt_properties_set( self->properties, "consumer.deinterlacer", "onefield" ); mlt_properties_set_int( self->properties, "top_field_first", -1 ); // Default buffer for low latency diff -Nru mlt-7.4.0/src/modules/sdl/consumer_sdl.c mlt-7.6.0/src/modules/sdl/consumer_sdl.c --- mlt-7.4.0/src/modules/sdl/consumer_sdl.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/sdl/consumer_sdl.c 2022-04-19 08:45:42.000000000 +0000 @@ -118,7 +118,7 @@ // Default scaler (for now we'll use nearest) mlt_properties_set( self->properties, "rescale", "nearest" ); - mlt_properties_set( self->properties, "deinterlace_method", "onefield" ); + mlt_properties_set( self->properties, "consumer.deinterlacer", "onefield" ); mlt_properties_set_int( self->properties, "top_field_first", -1 ); // Default buffer for low latency diff -Nru mlt-7.4.0/src/modules/sdl/consumer_sdl_preview.c mlt-7.6.0/src/modules/sdl/consumer_sdl_preview.c --- mlt-7.4.0/src/modules/sdl/consumer_sdl_preview.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/sdl/consumer_sdl_preview.c 2022-04-19 08:45:42.000000000 +0000 @@ -91,7 +91,7 @@ self->play = mlt_factory_consumer( profile, "sdl", arg ); self->still = mlt_factory_consumer( profile, "sdl_still", arg ); mlt_properties_set( properties, "rescale", "nearest" ); - mlt_properties_set( properties, "deinterlace_method", "onefield" ); + mlt_properties_set( properties, "consumer.deinterlacer", "onefield" ); mlt_properties_set_int( properties, "prefill", 1 ); mlt_properties_set_int( properties, "top_field_first", -1 ); @@ -205,10 +205,10 @@ mlt_properties_set_int( still, "progressive", progressive ); mlt_properties_pass_list( play, properties, - "deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio,preview_off,preview_format,window_background" + "deinterlacer,deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio,preview_off,preview_format,window_background" ",top_field_first,volume,real_time,buffer,prefill,audio_off,frequency,drop_max" ); mlt_properties_pass_list( still, properties, - "deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio,preview_off,preview_format,window_background" + "deinterlacer,deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio,preview_off,preview_format,window_background" ",top_field_first"); mlt_properties_pass( play, properties, "play." ); diff -Nru mlt-7.4.0/src/modules/sdl2/consumer_sdl2_audio.c mlt-7.6.0/src/modules/sdl2/consumer_sdl2_audio.c --- mlt-7.4.0/src/modules/sdl2/consumer_sdl2_audio.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/sdl2/consumer_sdl2_audio.c 2022-04-19 08:45:42.000000000 +0000 @@ -113,7 +113,7 @@ // Default scaler (for now we'll use nearest) mlt_properties_set( self->properties, "rescale", "nearest" ); - mlt_properties_set( self->properties, "deinterlace_method", "onefield" ); + mlt_properties_set( self->properties, "consumer.deinterlacer", "onefield" ); mlt_properties_set_int( self->properties, "top_field_first", -1 ); // Default buffer for low latency diff -Nru mlt-7.4.0/src/modules/sdl2/consumer_sdl2.c mlt-7.6.0/src/modules/sdl2/consumer_sdl2.c --- mlt-7.4.0/src/modules/sdl2/consumer_sdl2.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/sdl2/consumer_sdl2.c 2022-04-19 08:45:42.000000000 +0000 @@ -122,7 +122,7 @@ // Default scaler (for now we'll use nearest) mlt_properties_set( self->properties, "rescale", "nearest" ); - mlt_properties_set( self->properties, "deinterlace_method", "onefield" ); + mlt_properties_set( self->properties, "consumer.deinterlacer", "onefield" ); mlt_properties_set_int( self->properties, "top_field_first", -1 ); // Default buffer for low latency diff -Nru mlt-7.4.0/src/modules/sdl2/factory.c mlt-7.6.0/src/modules/sdl2/factory.c --- mlt-7.4.0/src/modules/sdl2/factory.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/sdl2/factory.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * factory.c -- the factory method interfaces - * Copyright (C) 2018 Meltytech, LLC + * Copyright (C) 2018-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -37,5 +37,5 @@ MLT_REGISTER( mlt_service_consumer_type, "sdl2", consumer_sdl2_init ); MLT_REGISTER_METADATA( mlt_service_consumer_type, "sdl2", metadata, "consumer_sdl2.yml" ); MLT_REGISTER( mlt_service_consumer_type, "sdl2_audio", consumer_sdl2_audio_init ); - MLT_REGISTER_METADATA( mlt_service_consumer_type, "sdl2_audio", metadata, "consumer_sdl_audio.yml" ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "sdl2_audio", metadata, "consumer_sdl2_audio.yml" ); } diff -Nru mlt-7.4.0/src/modules/sox/filter_sox_effect.yml mlt-7.6.0/src/modules/sox/filter_sox_effect.yml --- mlt-7.4.0/src/modules/sox/filter_sox_effect.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/sox/filter_sox_effect.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: sox title: sox @@ -16,7 +16,8 @@ - Some effects have a temporal side-effect that do not work well. parameters: - - identifier: argument + - identifier: effect + argument: yes title: Effect name and options type: string format: effect [options] diff -Nru mlt-7.4.0/src/modules/vid.stab/filter_deshake.cpp mlt-7.6.0/src/modules/vid.stab/filter_deshake.cpp --- mlt-7.4.0/src/modules/vid.stab/filter_deshake.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/vid.stab/filter_deshake.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -64,7 +64,7 @@ tconf->relative = 1; // by default a bicubic interpolation is selected - const char *interps = mlt_properties_get( MLT_FRAME_PROPERTIES( frame ), "rescale.interp" ); + const char *interps = mlt_properties_get( MLT_FRAME_PROPERTIES( frame ), "consumer.rescale" ); tconf->interpolType = VS_BiCubic; if ( strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 ) tconf->interpolType = VS_Zero; @@ -122,7 +122,7 @@ VSPixelFormat vs_format = PF_NONE; // VS only works on progressive frames - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer.progressive", 1 ); *format = validate_format( *format ); DeshakeData *data = static_cast(filter->child); diff -Nru mlt-7.4.0/src/modules/vid.stab/filter_vidstab.cpp mlt-7.6.0/src/modules/vid.stab/filter_vidstab.cpp --- mlt-7.4.0/src/modules/vid.stab/filter_vidstab.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/vid.stab/filter_vidstab.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -74,7 +74,7 @@ } // by default a bicubic interpolation is selected - const char *interps = mlt_properties_get( MLT_FRAME_PROPERTIES( frame ), "rescale.interp" ); + const char *interps = mlt_properties_get( MLT_FRAME_PROPERTIES( frame ), "consumer.rescale" ); conf->interpolType = VS_BiCubic; if ( strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 ) conf->interpolType = VS_Zero; @@ -347,7 +347,7 @@ } // VS only works on progressive frames - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer.progressive", 1 ); *format = validate_format( *format ); diff -Nru mlt-7.4.0/src/modules/vorbis/producer_vorbis.yml mlt-7.6.0/src/modules/vorbis/producer_vorbis.yml --- mlt-7.4.0/src/modules/vorbis/producer_vorbis.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/vorbis/producer_vorbis.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: producer identifier: vorbis title: Ogg Vorbis @@ -12,7 +12,8 @@ description: | OGG Vorbis file reader. parameters: - - identifier: argument + - identifier: resource + argument: yes title: File type: string description: File to use (only .ogg supported at the moment) diff -Nru mlt-7.4.0/src/modules/xine/factory.c mlt-7.6.0/src/modules/xine/factory.c --- mlt-7.4.0/src/modules/xine/factory.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/xine/factory.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * factory.c -- the factory method interfaces - * Copyright (C) 2003-2014 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * 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 @@ -22,7 +22,15 @@ extern mlt_filter filter_deinterlace_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) +{ + char file[ PATH_MAX ]; + snprintf( file, PATH_MAX, "%s/xine/%s", mlt_environment( "MLT_DATA" ), (char*) data ); + return mlt_properties_parse_yaml( file ); +} + MLT_REPOSITORY { MLT_REGISTER( mlt_service_filter_type, "deinterlace", filter_deinterlace_init ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "deinterlace", metadata, "filter_deinterlace.yml" ); } diff -Nru mlt-7.4.0/src/modules/xine/filter_deinterlace.c mlt-7.6.0/src/modules/xine/filter_deinterlace.c --- mlt-7.4.0/src/modules/xine/filter_deinterlace.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/xine/filter_deinterlace.c 2022-04-19 08:45:42.000000000 +0000 @@ -193,7 +193,7 @@ int error = 0; mlt_filter filter = mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); - int deinterlace = mlt_properties_get_int( properties, "consumer_deinterlace" ); + int deinterlace = mlt_properties_get_int( properties, "consumer.progressive" ); // The progressive var should only represent the frame's original state and not the state // as modified by this filter! int progressive = mlt_properties_get_int( properties, "progressive" ); @@ -205,7 +205,7 @@ // Determine deinterlace method char *method_str = mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "method" ); int method = DEINTERLACE_NONE; - char *frame_method_str = mlt_properties_get( properties, "deinterlace_method" ); + char *frame_method_str = mlt_properties_get( properties, "consumer.deinterlacer" ); if ( frame_method_str ) method_str = frame_method_str; diff -Nru mlt-7.4.0/src/modules/xine/filter_deinterlace.yml mlt-7.6.0/src/modules/xine/filter_deinterlace.yml --- mlt-7.4.0/src/modules/xine/filter_deinterlace.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-7.6.0/src/modules/xine/filter_deinterlace.yml 2022-04-19 08:45:42.000000000 +0000 @@ -0,0 +1,17 @@ +schema_version: 7.0 +type: filter +identifier: deinterlace +title: Xine Deinterlacer +version: 1 +copyright: Meltytech, LLC +license: GPLv2 +language: en +url: http://xinehq.de/ +tags: + - Video + - Hidden +description: Deinterlace interlaced video. +notes: > + This is not intended to be created directly. Rather, the loader producer + loads it if it is available to set deinterlace interlaced input when the + consumer or profile is set to progressive. diff -Nru mlt-7.4.0/src/modules/xml/filter_gpstext.c mlt-7.6.0/src/modules/xml/filter_gpstext.c --- mlt-7.4.0/src/modules/xml/filter_gpstext.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/xml/filter_gpstext.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_gpstext.c -- overlays GPS data as text on video - * Copyright (C) 2011-2021 Meltytech, LLC + * Copyright (C) 2011-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -174,8 +174,8 @@ * [ 1.23m | 12.3m | 123m ] */ static int decimals_needed(double x) { - if (abs(x) < 10) return 2; - if (abs(x) < 100) return 1; + if (fabs(x) < 10) return 2; + if (fabs(x) < 100) return 1; return 0; } @@ -313,14 +313,14 @@ { if (strlen(keyword) > strlen("gps_vdist_up")) format = keyword + strlen("gps_vdist_up"); - double val = convert_distance_to_format(abs(crt_point.elev_up), format); + double val = convert_distance_to_format(fabs(crt_point.elev_up), format); snprintf(gps_text, 10, "%.*f", decimals_needed(val), val); } else if ( !strncmp( keyword, "gps_vdist_down", strlen("gps_vdist_down") ) && crt_point.elev_down != GPS_UNINIT ) { if (strlen(keyword) > strlen("gps_vdist_down")) format = keyword + strlen("gps_vdist_down"); - double val = convert_distance_to_format(abs(crt_point.elev_down), format); + double val = convert_distance_to_format(fabs(crt_point.elev_down), format); snprintf(gps_text, 10, "%.*f", decimals_needed(val), val); } else if ( !strncmp( keyword, "gps_dist_uphill", strlen("gps_dist_uphill") ) && crt_point.dist_up != GPS_UNINIT ) @@ -464,11 +464,15 @@ //one time video timezone processing if (pdata->video_file_timezone_ms == -1) { - int64_t sec = original_video_time/1000; + time_t sec = original_video_time/1000; struct tm* ptm = localtime(&sec); ptm->tm_isdst = -1; //force dst detection mktime(ptm); +#if defined(__GLIBC__) || defined(__APPLE__) pdata->video_file_timezone_ms = (timezone-(ptm->tm_isdst*3600)) * 1000; +#else + pdata->video_file_timezone_ms = 0; +#endif //mlt_log_info(filter, "process_filter_properties, setting videofile_timezone_seconds=%d", pdata->video_file_timezone_ms); } @@ -728,6 +732,9 @@ */ mlt_filter filter_gpstext_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { + (void) type; // unused + (void) id; // unused + mlt_filter filter = mlt_filter_new(); private_data* pdata = (private_data*) calloc(1, sizeof(private_data)); default_priv_data(pdata); diff -Nru mlt-7.4.0/src/modules/xml/filter_gpstext.yml mlt-7.6.0/src/modules/xml/filter_gpstext.yml --- mlt-7.4.0/src/modules/xml/filter_gpstext.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/xml/filter_gpstext.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: filter identifier: gpstext title: GPS Text @@ -17,6 +17,7 @@ parameters: - identifier: argument + argument: yes title: GPS text type: string description: | diff -Nru mlt-7.4.0/src/modules/xml/gps_parser.c mlt-7.6.0/src/modules/xml/gps_parser.c --- mlt-7.4.0/src/modules/xml/gps_parser.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/xml/gps_parser.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * gps_parser.h -- Contains gps parsing (.gpx and .tcx) and processing code - * Copyright (C) 2011-2021 Meltytech, LLC + * Copyright (C) 2011-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,6 +18,10 @@ */ #include "gps_parser.h" +#include + +#define _x (const xmlChar*) +#define _s (const char*) /* Converts the datetime string from gps file into seconds since epoch in local timezone * Note: assumes UTC @@ -40,27 +44,30 @@ return 0; } + ret = mktime(&tm_time); +#if defined(__GLIBC__) || defined(__APPLE__) /* NOTE: mktime assumes local time-zone for the tm_time but GPS time is UTC. * time.h provides an extern: "timezone" which stores the local timezone in seconds * this is used by mktime to "correct" the time so we must substract it to keep UTC */ - ret = mktime(&tm_time) - (timezone-3600*tm_time.tm_isdst); + ret -= timezone - 3600 * tm_time.tm_isdst; +#endif - //check if we have miliesconds //NOTE: 3 digits only - if ( (ms_part = strchr(text, '.')) != NULL ) { - ms = strtol(ms_part+1, NULL, 10); - while (abs(ms) > 999) - ms /= 10; - } - ret = ret*1000 + ms; + //check if we have miliesconds //NOTE: 3 digits only + if ( (ms_part = strchr(text, '.')) != NULL ) { + ms = strtol(ms_part+1, NULL, 10); + while (abs(ms) > 999) + ms /= 10; + } + ret = ret*1000 + ms; - //mlt_log_info(NULL, "datetimeXMLstring_to_mseconds: text:%s, ms:%d (/1000)", text, ret/1000); - return ret; + //mlt_log_info(NULL, "datetimeXMLstring_to_mseconds: text:%s, ms:%d (/1000)", text, ret/1000); + return ret; } //checks if provided char* is only made of whitespace chars static int is_whitespace_string(char* str) { - int i; + unsigned i; for (i=0; i 0.05 || abs(p1_lat-p2_lat) > 0.05) { //~5.5km at equator to ~2km at arctic circle + if (fabs(p1_lat-p2_lat) > 0.05 || fabs(p1_lat-p2_lat) > 0.05) { //~5.5km at equator to ~2km at arctic circle mlt_log_info(NULL, "distance_equirectangular_2p: points are too far away, doing haversine (%f,%f to %f,%f)", p1_lat, p1_lon, p2_lat, p2_lon); return distance_haversine_2p(p1_lat, p1_lon, p2_lat, p2_lon); } @@ -287,7 +294,7 @@ } if (gdata.gps_points_p == NULL) { if ((*gdata.ptr_to_gps_points_p = calloc(*gdata.gps_points_size, sizeof(gps_point_proc))) == NULL) { - mlt_log_warning(gdata.filter, "calloc error, size=%d", *gdata.gps_points_size*sizeof(gps_point_proc)); + mlt_log_warning(gdata.filter, "calloc error, size=%"PRIu64"\n", *gdata.gps_points_size*sizeof(gps_point_proc)); return; } else { //alloc ok @@ -537,7 +544,7 @@ } if (gdata.gps_points_p == NULL) { if ((*gdata.ptr_to_gps_points_p = calloc(*gdata.gps_points_size, sizeof(gps_point_proc))) == NULL) { - mlt_log_warning(gdata.filter, "calloc failed, size =%d", *gdata.gps_points_size * sizeof(gps_point_proc)); + mlt_log_warning(gdata.filter, "calloc failed, size =%"PRIu64"\n", *gdata.gps_points_size * sizeof(gps_point_proc)); return; } else @@ -684,33 +691,33 @@ gps_point_raw crt_point = uninit_gps_raw_point; crt_node = found_nodes->nodeTab[i]; - if (xmlHasProp(crt_node, "lat")) { - char* str = xmlGetProp(crt_node, "lat"); - crt_point.lat = strtod(str, NULL); + if (xmlHasProp(crt_node, _x("lat"))) { + xmlChar* str = xmlGetProp(crt_node, _x("lat")); + crt_point.lat = strtod(_s(str), NULL); xmlFree(str); } - if (xmlHasProp(crt_node, "lon")) { - char* str = xmlGetProp(crt_node, "lon"); - crt_point.lon = strtod(str, NULL); + if (xmlHasProp(crt_node, _x("lon"))) { + xmlChar* str = xmlGetProp(crt_node, _x("lon")); + crt_point.lon = strtod(_s(str), NULL); xmlFree(str); } for (gps_val = crt_node->children; gps_val; gps_val = gps_val->next) { - if (strncmp(gps_val->name, "ele", strlen("ele")) == 0) - crt_point.ele = strtod(gps_val->children->content, NULL); - else if (strncmp(gps_val->name, "time", strlen("time")) == 0) - crt_point.time = datetimeXMLstring_to_mseconds(gps_val->children->content, NULL); - else if (strncmp(gps_val->name, "bearing", strlen("bearing")) == 0) - crt_point.bearing = (int)strtod(gps_val->children->content, NULL); - else if (strncmp(gps_val->name, "speed", strlen("speed")) == 0) - crt_point.speed = strtod(gps_val->children->content, NULL); - else if (strncmp(gps_val->name, "extensions", strlen("extensions")) == 0) + if (strncmp(_s(gps_val->name), "ele", strlen("ele")) == 0) + crt_point.ele = strtod(_s(gps_val->children->content), NULL); + else if (strncmp(_s(gps_val->name), "time", strlen("time")) == 0) + crt_point.time = datetimeXMLstring_to_mseconds(_s(gps_val->children->content), NULL); + else if (strncmp(_s(gps_val->name), "bearing", strlen("bearing")) == 0) + crt_point.bearing = (int)strtod(_s(gps_val->children->content), NULL); + else if (strncmp(_s(gps_val->name), "speed", strlen("speed")) == 0) + crt_point.speed = strtod(_s(gps_val->children->content), NULL); + else if (strncmp(_s(gps_val->name), "extensions", strlen("extensions")) == 0) { for (gps_subval = gps_val->children; gps_subval; gps_subval=gps_subval->next) { - if (strncmp(gps_subval->name, "gpxtpx:TrackPointExtension", strlen("gpxtpx:TrackPointExtension")) == 0) { + if (strncmp(_s(gps_subval->name), "gpxtpx:TrackPointExtension", strlen("gpxtpx:TrackPointExtension")) == 0) { for (gps_subsubval = gps_subval->children; gps_subsubval; gps_subsubval=gps_subsubval->next) { - if (strncmp(gps_subsubval->name, "gpxtpx:hr", strlen("gpxtpx:hr")) == 0) { - crt_point.hr = (short)strtod(gps_subsubval->children->content, NULL); + if (strncmp(_s(gps_subsubval->name), "gpxtpx:hr", strlen("gpxtpx:hr")) == 0) { + crt_point.hr = (short)strtod(_s(gps_subsubval->children->content), NULL); } } } @@ -731,7 +738,7 @@ gps_list = &(*gps_list)->next; last_time = crt_point.time; } - else printf("xml_parse_gpx: skipping point due to time [%d] %f,%f - crt:%I64d, last:%I64d\n", i, crt_point.lat, crt_point.lon, crt_point.time, last_time); + else mlt_log_info(NULL, "xml_parse_gpx: skipping point due to time [%d] %f,%f - crt:%"PRId64", last:%"PRId64"\n", i, crt_point.lat, crt_point.lon, crt_point.time, last_time); } } @@ -766,26 +773,26 @@ for (gps_val = crt_node->children; gps_val; gps_val = gps_val->next) { - if (strncmp(gps_val->name, "Time", strlen("Time")) == 0) - crt_point.time = datetimeXMLstring_to_mseconds(gps_val->children->content, NULL); - else if (strncmp(gps_val->name, "Position", strlen("Position")) == 0) + if (strncmp(_s(gps_val->name), "Time", strlen("Time")) == 0) + crt_point.time = datetimeXMLstring_to_mseconds(_s(gps_val->children->content), NULL); + else if (strncmp(_s(gps_val->name), "Position", strlen("Position")) == 0) { for (gps_subval = gps_val->children; gps_subval; gps_subval=gps_subval->next) { - if (strncmp(gps_subval->name, "LatitudeDegrees", strlen("LatitudeDegrees")) == 0) - crt_point.lat = strtod(gps_subval->children->content, NULL); - else if (strncmp(gps_subval->name, "LongitudeDegrees", strlen("LongitudeDegrees")) == 0) - crt_point.lon = strtod(gps_subval->children->content, NULL); + if (strncmp(_s(gps_subval->name), "LatitudeDegrees", strlen("LatitudeDegrees")) == 0) + crt_point.lat = strtod(_s(gps_subval->children->content), NULL); + else if (strncmp(_s(gps_subval->name), "LongitudeDegrees", strlen("LongitudeDegrees")) == 0) + crt_point.lon = strtod(_s(gps_subval->children->content), NULL); } } - else if (strncmp(gps_val->name, "AltitudeMeters", strlen("AltitudeMeters")) == 0) - crt_point.ele = strtod(gps_val->children->content, NULL); - else if (strncmp(gps_val->name, "DistanceMeters", strlen("DistanceMeters")) == 0) - crt_point.total_dist = strtod(gps_val->children->content, NULL); - else if (strncmp(gps_val->name, "HeartRateBpm", strlen("HeartRateBpm")) == 0) + else if (strncmp(_s(gps_val->name), "AltitudeMeters", strlen("AltitudeMeters")) == 0) + crt_point.ele = strtod(_s(gps_val->children->content), NULL); + else if (strncmp(_s(gps_val->name), "DistanceMeters", strlen("DistanceMeters")) == 0) + crt_point.total_dist = strtod(_s(gps_val->children->content), NULL); + else if (strncmp(_s(gps_val->name), "HeartRateBpm", strlen("HeartRateBpm")) == 0) { for (gps_subval = gps_val->children; gps_subval; gps_subval=gps_subval->next) - if (strncmp(gps_subval->name, "Value", strlen("Value")) == 0) - crt_point.hr = (short)strtod(gps_subval->children->content, NULL); + if (strncmp(_s(gps_subval->name), "Value", strlen("Value")) == 0) + crt_point.hr = (short)strtod(_s(gps_subval->children->content), NULL); } } // mlt_log_info(NULL, "_xml_parse_tcx read point [%d]: time:%d, lat:%.12f, lon:%.12f, ele:%f, distance:%f, hr:%d\n", @@ -802,7 +809,7 @@ gps_list = &(*gps_list)->next; last_time = crt_point.time; } - else printf("xml_parse_tcx: skipping point due to time [%d] %f,%f - crt:%I64d, last:%I64d\n", i, crt_point.lat, crt_point.lon, crt_point.time, last_time); + else mlt_log_info(NULL, "xml_parse_tcx: skipping point due to time [%d] %f,%f - crt:%"PRId64", last:%"PRId64"\n", i, crt_point.lat, crt_point.lon, crt_point.time, last_time); } } @@ -812,7 +819,7 @@ */ int xml_parse_file(gps_private_data gdata) { - int count_pts = 0, rv = 1, i = 0; + int count_pts = 0, rv = 1; xmlDoc *doc = NULL; xmlNode *root_element = NULL; xmlXPathContextPtr xpathCtx = NULL; @@ -849,9 +856,9 @@ } //xpath query for each doc type - if (strncmp(root_element->name, "TrainingCenterDatabase", strlen("TrainingCenterDatabase"))==0) { - xmlChar* xpathExpr = "//*[local-name()='Trackpoint']"; - xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); + if (strncmp(_s(root_element->name), "TrainingCenterDatabase", strlen("TrainingCenterDatabase"))==0) { + const char* xpathExpr = "//*[local-name()='Trackpoint']"; + xpathObj = xmlXPathEvalExpression(_x(xpathExpr), xpathCtx); xmlNodeSetPtr nodeset = xpathObj->nodesetval; if (xmlXPathNodeSetIsEmpty(nodeset)) { mlt_log_warning(gdata.filter, "xml_parse_file xmlXPathEvalExpression: no result, expr='%s'\n", xpathExpr); @@ -860,9 +867,9 @@ } xml_parse_tcx(nodeset, &gps_list_head, &count_pts); } - else if (strncmp(root_element->name, "gpx", strlen("gpx"))==0) { - xmlChar* xpathExpr = "//*[local-name()='trkpt']"; - xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); + else if (strncmp(_s(root_element->name), "gpx", strlen("gpx"))==0) { + const char* xpathExpr = "//*[local-name()='trkpt']"; + xpathObj = xmlXPathEvalExpression(_x(xpathExpr), xpathCtx); xmlNodeSetPtr nodeset = xpathObj->nodesetval; if (xmlXPathNodeSetIsEmpty(nodeset)) { mlt_log_warning(gdata.filter, "xml_parse_file xmlXPathEvalExpression: no result, expr='%s'\n", xpathExpr); @@ -880,7 +887,7 @@ *gdata.ptr_to_gps_points_r = (gps_point_raw*) calloc(count_pts, sizeof(gps_point_raw)); gps_point_raw* gps_array = *gdata.ptr_to_gps_points_r; //just an alias if (gps_array == NULL) { - mlt_log_error(gdata.filter, "malloc error (size=%d)", count_pts * sizeof(gps_point_raw)); + mlt_log_error(gdata.filter, "malloc error (size=%"PRIu64")\n", count_pts * sizeof(gps_point_raw)); rv = 0; goto cleanup; } @@ -909,4 +916,4 @@ xmlXPathFreeContext(xpathCtx); xmlFreeDoc(doc); return rv; -} \ No newline at end of file +} diff -Nru mlt-7.4.0/src/modules/xml/producer_xml.c mlt-7.6.0/src/modules/xml/producer_xml.c --- mlt-7.4.0/src/modules/xml/producer_xml.c 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/xml/producer_xml.c 2022-04-19 08:45:42.000000000 +0000 @@ -1,6 +1,6 @@ /* * producer_xml.c -- a libxml2 parser of mlt service networks - * Copyright (C) 2003-2020 Meltytech, LLC + * Copyright (C) 2003-2022 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1449,7 +1449,7 @@ if ( !context->qglsl ) { mlt_properties_pass_list( consumer_properties, properties, - "real_time, deinterlace_method, rescale, progressive, top_field_first, channels, channel_layout" ); + "real_time, deinterlacer, deinterlace_method, rescale, progressive, top_field_first, channels, channel_layout" ); // We only really know how to optimize real_time for the avformat consumer. const char *service_name = mlt_properties_get( properties, "mlt_service" ); diff -Nru mlt-7.4.0/src/modules/xml/producer_xml.yml mlt-7.6.0/src/modules/xml/producer_xml.yml --- mlt-7.4.0/src/modules/xml/producer_xml.yml 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/modules/xml/producer_xml.yml 2022-04-19 08:45:42.000000000 +0000 @@ -1,4 +1,4 @@ -schema_version: 0.1 +schema_version: 7.0 type: producer identifier: xml title: XML File @@ -23,11 +23,13 @@ its graph. bugs: - - This producer is not thread-safe during its construction because it + - > + This producer is not thread-safe during its construction because it may modify the mlt_profile, even if is_explicit is set. parameters: - - identifier: argument + - identifier: resource + argument: yes title: File type: string description: An XML text file containing MLT XML. diff -Nru mlt-7.4.0/src/swig/python/getimage.py mlt-7.6.0/src/swig/python/getimage.py --- mlt-7.4.0/src/swig/python/getimage.py 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/swig/python/getimage.py 2022-04-19 08:45:42.000000000 +0000 @@ -20,8 +20,8 @@ prod.seek(int(prod.get_length() * 0.1)) frame = prod.get_frame() -# And make sure we deinterlace if input is interlaced - optional. -frame.set("consumer_deinterlace", 1) +# Make sure we deinterlace if input is interlaced. +frame.set("consumer.progressive", 1) # Now we are ready to get the image and save it. size = (profile.width(), profile.height()) diff -Nru mlt-7.4.0/src/swig/ruby/metadata.rb mlt-7.6.0/src/swig/ruby/metadata.rb --- mlt-7.4.0/src/swig/ruby/metadata.rb 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/swig/ruby/metadata.rb 2022-04-19 08:45:42.000000000 +0000 @@ -78,8 +78,9 @@ % end % end type: <%= param['type'] %> -readonly: <%= param['readonly'] or 'no' %> -required: <%= param['required'] or 'no' %> +readonly: <%= param['readonly'] and 'yes' or 'no' %> +required: <%= param['required'] and 'yes' or 'no' %> +<%= "animation: yes \n" if param['animation'] %> % $optional_params.each do |key| <%= "#{key}: #{param[key].to_s.gsub('](', ']\(')} \n" if param[key] %> % end @@ -112,12 +113,15 @@ unsorted.sort().each do |name| meta = $repo.metadata(mlt_type, name) if meta.is_valid + if !meta.get_data('parameters') + puts "No parameters for #{name} #{type_title}" + end filename = File.join($folder, type_title + name.capitalize.gsub('.', '-')) - puts "Processing #{filename}" +# puts "Processing #{filename}" begin yml = YAML.load(meta.serialise_yaml) if yml - File.open(filename + '.md', 'w') do |f| + File.open(filename + '.md', 'w') do |f| f.puts $processor.result(binding) end else @@ -128,6 +132,8 @@ rescue SyntaxError puts "Failed to parse YAML for #{filename}" end + else + puts "No metadata for #{name} #{type_title}" end end index.close @@ -138,6 +144,7 @@ [ [Mlt::Mlt_service_consumer_type, $repo.consumers, 'Consumer'], [Mlt::Mlt_service_filter_type, $repo.filters, 'Filter'], + [Mlt::Mlt_service_link_type, $repo.links, 'Link'], [Mlt::Mlt_service_producer_type, $repo.producers, 'Producer'], [Mlt::Mlt_service_transition_type, $repo.transitions, 'Transition'] ].each {|x| output *x} diff -Nru mlt-7.4.0/src/tests/test_animation/test_animation.cpp mlt-7.6.0/src/tests/test_animation/test_animation.cpp --- mlt-7.4.0/src/tests/test_animation/test_animation.cpp 2022-01-08 18:11:59.000000000 +0000 +++ mlt-7.6.0/src/tests/test_animation/test_animation.cpp 2022-04-19 08:45:42.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2018 Dan Dennedy + * Copyright (C) 2015-2021 Dan Dennedy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -383,6 +383,82 @@ QCOMPARE(a.key_get_frame(2), 40); QCOMPARE(a.key_get_frame(3), -1); } + + void NextKey() + { + Properties p; + p.set("foo", "50=100; 60=60; 100=0"); + // Cause the string to be interpreted as animated value. + p.anim_get_int("foo", 0); + Animation a = p.get_animation("foo"); + QVERIFY(a.is_valid()); + + int key; + bool ret; + + ret = a.next_key(0, key); + QCOMPARE(ret, false); + QCOMPARE(key, 50); + + ret = a.next_key(59, key); + QCOMPARE(ret, false); + QCOMPARE(key, 60); + + ret = a.next_key(60, key); + QCOMPARE(ret, false); + QCOMPARE(key, 60); + + ret = a.next_key(61, key); + QCOMPARE(ret, false); + QCOMPARE(key, 100); + + ret = a.next_key(100, key); + QCOMPARE(ret, false); + QCOMPARE(key, 100); + + key = 7; // random value + ret = a.next_key(101, key); + QCOMPARE(ret, true); // error - No next key + QCOMPARE(key, 7); // Not modified on error + } + + void PreviousKey() + { + Properties p; + p.set("foo", "50=100; 60=60; 100=0"); + // Cause the string to be interpreted as animated value. + p.anim_get_int("foo", 0); + Animation a = p.get_animation("foo"); + QVERIFY(a.is_valid()); + + int key; + bool ret; + + key = 7; // random value + ret = a.previous_key(0, key); + QCOMPARE(ret, true); // error - no previous key + QCOMPARE(key, 7); // Not modified on error + + ret = a.previous_key(59, key); + QCOMPARE(ret, false); + QCOMPARE(key, 50); + + ret = a.previous_key(60, key); + QCOMPARE(ret, false); + QCOMPARE(key, 60); + + ret = a.previous_key(61, key); + QCOMPARE(ret, false); + QCOMPARE(key, 60); + + ret = a.previous_key(100, key); + QCOMPARE(ret, false); + QCOMPARE(key, 100); + + ret = a.previous_key(101, key); + QCOMPARE(ret, false); + QCOMPARE(key, 100); + } }; QTEST_APPLESS_MAIN(TestAnimation)