diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index dbfbde98a..46f2df117 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -78,4 +78,4 @@ jobs: LD_LIBRARY_PATH: /usr/local/lib run: | sudo locale-gen de_DE.UTF-8 - cd build && ctest + cd build && ctest --output-on-failure diff --git a/.gitignore b/.gitignore index ad0c9466b..88189f1ba 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,13 @@ src/tests/*/* !src/tests/*/*.cpp !src/tests/*/*.pro build +*cmake_install.cmake +.ninja_* +build.ninja +rules.ninja +CMakeCache.txt +*CMakeFiles/ +Mlt7Config*.cmake +install_manifest.txt +out/ +src/modules/qt/mltqt_autogen/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b4415a15..16c26ab35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,47 +1,43 @@ cmake_minimum_required(VERSION 3.14) project(MLT - VERSION 6.26.1 + VERSION 7.0.0 DESCRIPTION "Multimedia Framework" HOMEPAGE_URL "https://www.mltframework.org" LANGUAGES C CXX ) -option(GPL "Enable GPLv2 modules" ON) -option(GPL3 "Enable GPLv3 modules" ON) +option(GPL "Enable GPLv2 components" ON) +option(GPL3 "Enable GPLv3 components" ON) option(BUILD_TESTING "Enable tests" OFF) option(BUILD_DOCS "Enable Doxygen documentation" OFF) option(MOD_AVFORMAT "Enable avformat module" ON) -option(MOD_DECKLINK "Enable decklink module" ON) -option(MOD_FEEDS "Enable feeds module" ON) -option(MOD_FREI0R "Enable frei0r module" ON) -option(MOD_GDK "Enable gdk module" ON) -option(MOD_GTK2 "Enable gtk2 module" ON) -option(MOD_JACKRACK "Enable jackrack module" ON) -option(MOD_KDENLIVE "Enable kdenlive module" ON) -option(MOD_LUMAS "Enable lumas module" ON) -option(MOD_MOTION_EST "Enable motion estimation module" ON) -option(MOD_NORMALIZE "Enable normalize module" ON) -option(MOD_OLDFILM "Enable oldfilm module" ON) -option(MOD_OPENCV "Enable OpenCV module" ON) -option(MOD_OPENGL "Enable OpenGL module" ON) -option(MOD_PLUS "Enable plus module" ON) -option(MOD_PLUSGPL "Enable plus GPL module" ON) -option(MOD_QT "Enable Qt module" ON) -option(MOD_RESAMPLE "Enable resample module" ON) +option(MOD_DECKLINK "Enable DeckLink module" ON) +option(MOD_FREI0R "Enable Frei0r module" ON) +option(MOD_GDK "Enable GDK module" ON) +option(MOD_JACKRACK "Enable JACK Rack module" ON) +option(MOD_KDENLIVE "Enable Kdenlive module" ON) +option(MOD_NDI "Enable NDI module" OFF) +option(MOD_NORMALIZE "Enable Normalize module (GPL)" ON) +option(MOD_OLDFILM "Enable Oldfilm module" ON) +option(MOD_OPENCV "Enable OpenCV module" OFF) +option(MOD_MOVIT "Enable OpenGL module" ON) +option(MOD_PLUS "Enable Plus module" ON) +option(MOD_PLUSGPL "Enable PlusGPL module (GPL)" ON) +option(MOD_QT "Enable Qt module (GPL)" ON) +option(MOD_RESAMPLE "Enable Resample module (GPL)" ON) option(MOD_RTAUDIO "Enable RtAudio module" ON) -option(MOD_RUBBERBAND "Enable rubberband module" ON) +option(MOD_RUBBERBAND "Enable Rubberband module (GPL)" ON) option(MOD_SDL1 "Enable SDL1 module" ON) option(MOD_SDL2 "Enable SDL2 module" ON) option(MOD_SOX "Enable SoX module" ON) -option(MOD_VIDSTAB "Enable vid.stab module" ON) -option(MOD_VMFX "Enable vmfx module" ON) +option(MOD_VIDSTAB "Enable vid.stab module (GPL)" ON) option(MOD_VORBIS "Enable Vorbis module" ON) -option(MOD_XINE "Enable xine module" ON) +option(MOD_XINE "Enable XINE module (GPL)" ON) option(MOD_XML "Enable XML module" ON) -option(SWIG_CSHARP "Enable SWIG CSharp bindings" OFF) +option(SWIG_CSHARP "Enable SWIG C# bindings" OFF) option(SWIG_JAVA "Enable SWIG Java bindings" OFF) option(SWIG_LUA "Enable SWIG Lua bindings" OFF) option(SWIG_NODEJS "Enable SWIG Node.js bindings" OFF) @@ -52,13 +48,53 @@ option(SWIG_RUBY "Enable SWIG Ruby bindings" OFF) option(SWIG_TCL "Enable SWIG Tcl bindings" OFF) if(WIN32) - option(NODEPLOY "Keep bin/ lib/ layout on Windows" ON) + option(WINDOWS_DEPLOY "Install exes/libs directly to prefix (no subdir /bin)" ON) endif() +if(APPLE) + option(RELOCATABLE "Use standard app bundle layout" ON) +endif() + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +include(FeatureSummary) include(GNUInstallDirs) +if(WINDOWS_DEPLOY) + set(CMAKE_INSTALL_BINDIR .) +endif() + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/out/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/out/lib") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/out/lib") +set(MLT_MODULE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/out/lib/mlt") +set(MLT_DATA_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/out/share/mlt") + +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) + file(RENAME "${CMAKE_BINARY_DIR}/out/share/modules" "${MLT_DATA_OUTPUT_DIRECTORY}") + file(COPY "${CMAKE_SOURCE_DIR}/presets" DESTINATION "${MLT_DATA_OUTPUT_DIRECTORY}") + file(COPY "${CMAKE_SOURCE_DIR}/profiles" DESTINATION "${MLT_DATA_OUTPUT_DIRECTORY}") + else() + file(MAKE_DIRECTORY "${MLT_DATA_OUTPUT_DIRECTORY}") + file(GLOB MOD_SUBDIRS "${CMAKE_SOURCE_DIR}/src/modules/*") + foreach(MOD_SUBDIR ${MOD_SUBDIRS}) + file(RELATIVE_PATH MOD_NAME "${CMAKE_SOURCE_DIR}/src/modules" ${MOD_SUBDIR}) + file(CREATE_LINK "${CMAKE_SOURCE_DIR}/src/modules/${MOD_NAME}" "${MLT_DATA_OUTPUT_DIRECTORY}/${MOD_NAME}" SYMBOLIC) + endforeach() + file(CREATE_LINK "${CMAKE_SOURCE_DIR}/presets" "${MLT_DATA_OUTPUT_DIRECTORY}/presets" SYMBOLIC) + file(CREATE_LINK "${CMAKE_SOURCE_DIR}/profiles" "${MLT_DATA_OUTPUT_DIRECTORY}/profiles" SYMBOLIC) + endif() +endif() + +set(MLT_INSTALL_MODULE_DIR ${CMAKE_INSTALL_LIBDIR}/mlt) +set(MLT_INSTALL_DATA_DIR ${CMAKE_INSTALL_DATADIR}/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}) +endif() + set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) @@ -67,20 +103,40 @@ set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(AMD64)") - if(${ARCH} MATCHES "i686") - else() - set(X86_64 ON) - if(NOT MSVC) - add_compile_definitions(USE_MMX USE_SSE USE_SSE2 ARCH_X86_64) +list(APPEND MLT_COMPILE_OPTIONS "") + +# MSVC cl doesn't support GNU inline assembly (but MSVC-compatible clang-cl does) +if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") + if(CMAKE_SYSTEM_PROCESSOR MATCHES "i686|x86|x86_64|AMD64") + set(CPU_MMX ON) + set(CPU_SSE ON) + set(CPU_SSE2 ON) + if(NOT MSVC) # also NOT clang-cl + list(APPEND MLT_COMPILE_OPTIONS "-mmmx;-msse;-msse2") endif() endif() + if(CMAKE_SYSTEM_PROCESSOR MATCHES "i686" OR (WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86")) + set(CPU_X86_32 ON) + endif() + if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64") + set(CPU_X86_64 ON) + endif() endif() -if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") - add_compile_options(-ffast-math) -elseif(MSVC) - add_compile_options(/fp:fast) +if(MSVC) + list(APPEND MLT_COMPILE_OPTIONS "$<$:/fp:fast>") +elseif(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") + list(APPEND MLT_COMPILE_OPTIONS "$<$:-ffast-math>") +endif() + +if(NOT GPL) + set(MOD_NORMALIZE OFF) + set(MOD_PLUSGPL OFF) + set(MOD_QT OFF) + set(MOD_RESAMPLE OFF) + set(MOD_RUBBERBAND OFF) + set(MOD_VIDSTAB OFF) + set(MOD_XINE OFF) endif() find_package(Threads REQUIRED) @@ -94,7 +150,7 @@ if(WIN32) endif() endif() -pkg_check_modules(sdl2 IMPORTED_TARGET GLOBAL sdl2) +pkg_check_modules(sdl2 IMPORTED_TARGET sdl2) if(BUILD_TESTING) find_package(Qt5 REQUIRED COMPONENTS Core Test) @@ -102,10 +158,6 @@ if(BUILD_TESTING) enable_testing() endif() -if(MOD_QT) - find_package(Qt5 COMPONENTS Core Gui Xml Svg Widgets) -endif() - if(MOD_QT OR MOD_PLUS) pkg_check_modules(FFTW IMPORTED_TARGET fftw3) if(NOT FFTW_FOUND) @@ -129,54 +181,112 @@ if(MOD_AVFORMAT) pkg_check_modules(libavformat IMPORTED_TARGET libavformat) pkg_check_modules(libswscale IMPORTED_TARGET libswscale) pkg_check_modules(libavutil IMPORTED_TARGET libavutil) - pkg_check_modules(libavcodec IMPORTED_TARGET libavcodec) - pkg_check_modules(libavfilter IMPORTED_TARGET libavfilter) - pkg_check_modules(libavdevice IMPORTED_TARGET libavdevice) - pkg_check_modules(libswresample IMPORTED_TARGET libswresample) + if(TARGET PkgConfig::libavformat AND TARGET PkgConfig::libswscale AND TARGET PkgConfig::libavutil) + pkg_check_modules(libavcodec IMPORTED_TARGET libavcodec) + pkg_check_modules(libavfilter IMPORTED_TARGET libavfilter) + pkg_check_modules(libavdevice IMPORTED_TARGET libavdevice) + pkg_check_modules(libswresample IMPORTED_TARGET libswresample) + list(APPEND MLT_SUPPORTED_COMPONENTS avformat) + else() + set(MOD_AVFORMAT OFF) + endif() +endif() + +if(MOD_DECKLINK) + list(APPEND MLT_SUPPORTED_COMPONENTS decklink) endif() if(MOD_FREI0R) pkg_check_modules(FREI0R frei0r) + if(FREI0R_FOUND) + list(APPEND MLT_SUPPORTED_COMPONENTS frei0r) + else() + set(MOD_FREI0R OFF) + endif() endif() if(MOD_GDK) pkg_check_modules(GdkPixbuf IMPORTED_TARGET gdk-pixbuf-2.0) - pkg_check_modules(pango IMPORTED_TARGET pango) - pkg_check_modules(pangoft2 IMPORTED_TARGET pangoft2) -endif() - -if(MOD_GTK2) - find_package(GTK2 COMPONENTS gtk) - pkg_check_modules(harfbuzz IMPORTED_TARGET harfbuzz) + if(TARGET PkgConfig::GdkPixbuf) + pkg_check_modules(pango IMPORTED_TARGET pango) + pkg_check_modules(pangoft2 IMPORTED_TARGET pangoft2) + list(APPEND MLT_SUPPORTED_COMPONENTS gdk) + else() + set(MOD_GDK OFF) + endif() endif() if(MOD_JACKRACK) - pkg_check_modules(jack IMPORTED_TARGET jack) + find_package(JACK) pkg_check_modules(glib IMPORTED_TARGET glib-2.0) check_include_file(ladspa.h ladspa_h_FOUND) + list(APPEND MLT_SUPPORTED_COMPONENTS jackrack) +endif() + +if(MOD_KDENLIVE) + list(APPEND MLT_SUPPORTED_COMPONENTS kdenlive) +endif() + +if(MOD_NDI) + find_package(NDI REQUIRED) + list(APPEND MLT_SUPPORTED_COMPONENTS ndi) +endif() + +if(MOD_NORMALIZE) + list(APPEND MLT_SUPPORTED_COMPONENTS normalize) +endif() + +if(MOD_OLDFILM) + list(APPEND MLT_SUPPORTED_COMPONENTS oldfilm) endif() if(MOD_OPENCV) - find_package(OpenCV QUIET OPTIONAL_COMPONENTS tracking) + find_package(OpenCV REQUIRED COMPONENTS tracking) + if(OpenCV_tracking_FOUND) + list(APPEND MLT_SUPPORTED_COMPONENTS opencv) + else() + set(MOD_OPENCV OFF) + endif() endif() -if(MOD_OPENGL) +if(MOD_MOVIT) pkg_check_modules(movit IMPORTED_TARGET movit) find_package(OpenGL) - if(UNIX AND NOT APPLE) - find_package(X11) - if(NOT TARGET X11::X11) - set(MOD_OPENGL OFF) + if(TARGET PkgConfig::movit AND TARGET OpenGL::GL) + if(UNIX AND NOT APPLE) + find_package(X11 REQUIRED) endif() + list(APPEND MLT_SUPPORTED_COMPONENTS movit) + else() + set(MOD_MOVIT OFF) endif() endif() if(MOD_PLUS) pkg_check_modules(libebur128 IMPORTED_TARGET libebur128) + list(APPEND MLT_SUPPORTED_COMPONENTS plus) +endif() + +if(MOD_PLUSGPL) + list(APPEND MLT_SUPPORTED_COMPONENTS plusgpl) +endif() + +if(MOD_QT) + find_package(Qt5 COMPONENTS Core Gui Xml Svg Widgets) + if(Qt5_FOUND) + list(APPEND MLT_SUPPORTED_COMPONENTS qt) + else() + set(MOD_QT OFF) + endif() endif() if(MOD_RESAMPLE) pkg_check_modules(samplerate IMPORTED_TARGET samplerate) + if(TARGET PkgConfig::samplerate) + list(APPEND MLT_SUPPORTED_COMPONENTS resample) + else() + set(MOD_RESAMPLE OFF) + endif() endif() if(MOD_RTAUDIO) @@ -185,46 +295,91 @@ if(MOD_RTAUDIO) pkg_check_modules(alsa IMPORTED_TARGET alsa) pkg_check_modules(libpulse-simple IMPORTED_TARGET libpulse-simple) endif() + list(APPEND MLT_SUPPORTED_COMPONENTS rtaudio) endif() if(MOD_RUBBERBAND) pkg_check_modules(rubberband IMPORTED_TARGET rubberband) + if(TARGET PkgConfig::rubberband) + list(APPEND MLT_SUPPORTED_COMPONENTS rubberband) + else() + set(MOD_RUBBERBAND OFF) + endif() endif() if(MOD_SDL1) pkg_check_modules(sdl IMPORTED_TARGET sdl) - pkg_check_modules(sdl_image IMPORTED_TARGET SDL_image) + if(TARGET PkgConfig::sdl) + list(APPEND MLT_SUPPORTED_COMPONENTS sdl) + else() + set(MOD_SDL1 OFF) + endif() +endif() + +if(MOD_SDL2) + if(TARGET PkgConfig::sdl2) + list(APPEND MLT_SUPPORTED_COMPONENTS sdl2) + else() + set(MOD_SDL2 OFF) + endif() endif() if(MOD_SOX) pkg_check_modules(sox IMPORTED_TARGET sox) + if(TARGET PkgConfig::sox) + list(APPEND MLT_SUPPORTED_COMPONENTS sox) + else() + set(MOD_SOX OFF) + endif() endif() if(MOD_VIDSTAB) pkg_check_modules(vidstab IMPORTED_TARGET vidstab) + if(TARGET PkgConfig::vidstab) + list(APPEND MLT_SUPPORTED_COMPONENTS vidstab) + else() + set(MOD_VIDSTAB OFF) + endif() endif() if(MOD_VORBIS) pkg_check_modules(vorbis IMPORTED_TARGET vorbis) pkg_check_modules(vorbisfile IMPORTED_TARGET vorbisfile) + if(TARGET PkgConfig::vorbis AND TARGET PkgConfig::vorbisfile) + list(APPEND MLT_SUPPORTED_COMPONENTS vorbis) + else() + set(MOD_VORBIS OFF) + endif() +endif() + +if(MOD_XINE) + list(APPEND MLT_SUPPORTED_COMPONENTS xine) +endif() + +if(MOD_XML) + if(TARGET PkgConfig::xml) + list(APPEND MLT_SUPPORTED_COMPONENTS xml) + else() + set(MOD_XML OFF) + endif() endif() find_package(SWIG) if(SWIG_CSHARP) - find_package(Mono) + find_package(Mono REQUIRED) endif() if(SWIG_JAVA) - find_package(JNI) + find_package(JNI REQUIRED) endif() if(SWIG_LUA) - find_package(Lua) + find_package(Lua REQUIRED) endif() if(SWIG_NODEJS) - find_package(Node) + find_package(Node REQUIRED) if(NODE_VERSION_MAJOR VERSION_GREATER_EQUAL 12 AND SWIG_VERSION VERSION_LESS 4.1) # https://github.com/swig/swig/issues/1520 set(SWIG_NODEJS OFF) @@ -232,23 +387,23 @@ if(SWIG_NODEJS) endif() if(SWIG_PERL) - find_package(PerlLibs) + find_package(PerlLibs REQUIRED) endif() if(SWIG_PHP) - find_package(PHP) + find_package(PHP REQUIRED) endif() if(SWIG_PYTHON) - find_package(Python3 COMPONENTS Interpreter Development) + find_package(Python3 REQUIRED COMPONENTS Interpreter Development) endif() if(SWIG_RUBY) - find_package(Ruby) + find_package(Ruby REQUIRED) endif() if(SWIG_TCL) - find_package(TCL) + find_package(TCL REQUIRED) endif() if(BUILD_DOCS) @@ -276,10 +431,76 @@ if(BUILD_DOCS) doxygen_add_docs(docs src/framework) endif() -install(DIRECTORY presets profiles DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt) +install(DIRECTORY presets profiles DESTINATION ${MLT_INSTALL_DATA_DIR}) if(UNIX AND NOT APPLE) - install(FILES docs/melt.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) + install(FILES docs/melt.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 RENAME melt-${MLT_VERSION_MAJOR}.1) + install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink melt-${MLT_VERSION_MAJOR}.1 melt.1 \ + WORKING_DIRECTORY ${CMAKE_INSTALL_FULL_MANDIR}/man1)" + ) endif() add_subdirectory(src) + +install(EXPORT MltTargets + FILE Mlt${MLT_VERSION_MAJOR}Targets.cmake + NAMESPACE Mlt${MLT_VERSION_MAJOR}:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Mlt${MLT_VERSION_MAJOR} +) + +include(CMakePackageConfigHelpers) +configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/MltConfig.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/Mlt${MLT_VERSION_MAJOR}Config.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Mlt${MLT_VERSION_MAJOR} + NO_CHECK_REQUIRED_COMPONENTS_MACRO +) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/Mlt${MLT_VERSION_MAJOR}ConfigVersion.cmake" + COMPATIBILITY SameMajorVersion +) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/Mlt${MLT_VERSION_MAJOR}Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/Mlt${MLT_VERSION_MAJOR}ConfigVersion.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Mlt${MLT_VERSION_MAJOR} +) + +add_feature_info("GPLv2" GPL "") +add_feature_info("GPLv3" GPL3 "") +add_feature_info("Tests" BUILD_TESTING "") +add_feature_info("Doxygen" BUILD_DOCS "") +add_feature_info("Module: avformat" MOD_AVFORMAT "") +add_feature_info("Module: DeckLink" MOD_DECKLINK "") +add_feature_info("Module: Frei0r" MOD_FREI0R "") +add_feature_info("Module: GDK" MOD_GDK "") +add_feature_info("Module: JACKRack" MOD_JACKRACK "") +add_feature_info("Module: Kdenlive" MOD_KDENLIVE "") +add_feature_info("Module: NDI" MOD_NDI "") +add_feature_info("Module: Normalize" MOD_NORMALIZE "") +add_feature_info("Module: Oldfilm" MOD_OLDFILM "") +add_feature_info("Module: OpenCV" MOD_OPENCV "") +add_feature_info("Module: Movit" MOD_MOVIT "") +add_feature_info("Module: Plus" MOD_PLUS "") +add_feature_info("Module: PlusGPL" MOD_PLUSGPL "") +add_feature_info("Module: Qt" MOD_QT "") +add_feature_info("Module: Resample" MOD_RESAMPLE "") +add_feature_info("Module: RtAudio" MOD_RTAUDIO "") +add_feature_info("Module: Rubberband" MOD_RUBBERBAND "") +add_feature_info("Module: SDL1" MOD_SDL1 "") +add_feature_info("Module: SDL2" MOD_SDL2 "") +add_feature_info("Module: SoX" MOD_SOX "") +add_feature_info("Module: vid.stab" MOD_VIDSTAB "") +add_feature_info("Module: Vorbis" MOD_VORBIS "") +add_feature_info("Module: XINE" MOD_XINE "") +add_feature_info("Module: XML" MOD_XML "") +add_feature_info("SWIG: C#" SWIG_CSHARP "") +add_feature_info("SWIG: Java" SWIG_JAVA "") +add_feature_info("SWIG: Lua" SWIG_LUA "") +add_feature_info("SWIG: Node.js" SWIG_NODEJS "") +add_feature_info("SWIG: Perl" SWIG_PERL "") +add_feature_info("SWIG: PHP" SWIG_PHP "") +add_feature_info("SWIG: Python" SWIG_PYTHON "") +add_feature_info("SWIG: Ruby" SWIG_RUBY "") +add_feature_info("SWIG: Tcl" SWIG_TCL "") + +feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/MltConfig.cmake.in b/MltConfig.cmake.in new file mode 100644 index 000000000..7ac044629 --- /dev/null +++ b/MltConfig.cmake.in @@ -0,0 +1,12 @@ +@PACKAGE_INIT@ + +set(_supported_components "@MLT_SUPPORTED_COMPONENTS@") + +foreach(_comp ${Mlt@MLT_VERSION_MAJOR@_FIND_COMPONENTS}) + if (NOT _comp IN_LIST _supported_components) + set(Mlt@MLT_VERSION_MAJOR@_FOUND False) + set(Mlt@MLT_VERSION_MAJOR@_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}") + endif() +endforeach() + +include("${CMAKE_CURRENT_LIST_DIR}/Mlt@MLT_VERSION_MAJOR@Targets.cmake") diff --git a/cmake/FindJACK.cmake b/cmake/FindJACK.cmake new file mode 100644 index 000000000..a30214e78 --- /dev/null +++ b/cmake/FindJACK.cmake @@ -0,0 +1,36 @@ +find_package(PkgConfig) +pkg_check_modules(PC_JACK QUIET jack) + +find_path(JACK_INCLUDE_DIR + NAMES jack/jack.h + PATHS ${PC_JACK_INCLUDE_DIRS} +) +find_library(JACK_LIBRARY + NAMES jack + PATHS ${PC_JACK_LIBRARY_DIRS} +) + +set(JACK_VERSION ${PC_JACK_VERSION}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(JACK + FOUND_VAR JACK_FOUND + REQUIRED_VARS + JACK_LIBRARY + JACK_INCLUDE_DIR + VERSION_VAR JACK_VERSION +) + +if(JACK_FOUND AND NOT TARGET JACK::JACK) + add_library(JACK::JACK UNKNOWN IMPORTED) + set_target_properties(JACK::JACK PROPERTIES + IMPORTED_LOCATION "${JACK_LIBRARY}" + INTERFACE_COMPILE_OPTIONS "${PC_JACK_CFLAGS_OTHER}" + INTERFACE_INCLUDE_DIRECTORIES "${JACK_INCLUDE_DIR}" + ) +endif() + +mark_as_advanced( + JACK_INCLUDE_DIR + JACK_LIBRARY +) diff --git a/cmake/FindNDI.cmake b/cmake/FindNDI.cmake new file mode 100644 index 000000000..8711f161b --- /dev/null +++ b/cmake/FindNDI.cmake @@ -0,0 +1,53 @@ +set(NDI_SDK_INCLUDE_PATH "" CACHE PATH "NDI SDK include path") +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!") +endif() + +find_path(NDI_INCLUDE_DIR + NAMES + Processing.NDI.compat.h + Processing.NDI.deprecated.h + Processing.NDI.DynamicLoad.h + Processing.NDI.Find.h + Processing.NDI.FrameSync.h + Processing.NDI.Lib.cplusplus.h + Processing.NDI.Lib.h + Processing.NDI.Recv.ex.h + Processing.NDI.Recv.h + Processing.NDI.Routing.h + Processing.NDI.Send.h + Processing.NDI.structs.h + Processing.NDI.utilities.h + PATHS "${NDI_SDK_INCLUDE_PATH}" +) + +find_library(NDI_LIBRARY + NAMES ndi + PATHS "${NDI_SDK_LIBRARY_PATH}" +) +if(NOT NDI_LIBRARY) + message(FATAL_ERROR "NDI SDK: libndi.so / ndi.dll not found in:\n${NDI_SDK_LIBRARY_PATH}\nMaybe you have to create a symlink or rename the file.") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NDI + FOUND_VAR NDI_FOUND + REQUIRED_VARS + NDI_LIBRARY + NDI_INCLUDE_DIR +) + +if(NDI_FOUND AND NOT TARGET NDI::NDI) + add_library(NDI::NDI SHARED IMPORTED) + set_target_properties(NDI::NDI PROPERTIES + IMPORTED_LOCATION "${NDI_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${NDI_INCLUDE_DIR}" + ) +endif() + +mark_as_advanced( + NDI_INCLUDE_DIR + NDI_LIBRARY +) \ No newline at end of file diff --git a/configure b/configure index e711c0188..c17861c3c 100755 --- a/configure +++ b/configure @@ -1,7 +1,7 @@ #!/bin/sh -export version=6.26.1 -export soversion=6 +export version=7.0.0 +export soversion=7 show_help() { diff --git a/demo/README b/demo/README index 555d6ea86..2577def61 100644 --- a/demo/README +++ b/demo/README @@ -13,9 +13,7 @@ you to choose a consumer. A consumer is like a viewer, but it could also write to a stream/file. The "SDL" consumer is the popular Simple DirectMedia Layer audio and video output. The "xml" consumer generates an XML representation of the service network. That can be played directly due to the -XML producer plugin. See docs/mlt-xml.txt for more information. "/dev/dv1394/0" -refers to a device file for transmitting DV over FireWire using the Linux -dv1394 kernel module. +XML producer plugin. See docs/mlt-xml.txt for more information. These examples assume the numeric locale LC_NUMERIC decimal separator is a period. Therefore, the demo script sets LC_NUMERIC=C for you, but if you are @@ -78,16 +76,6 @@ Clock in and out http://mlt.sf.net/. It also performs field rendering. The second wipe demonstrates the ability to control the direction of the wipe as well. - -Obscure - - A popular requirement in news production is to obscure a face, obscenity, - or trademarked logo. This demonstrates using a simple rectangular - obscure filter applied to a region of the image. The second example is more - advanced and shows using the "region" filter to select the image area and a - property of the region filter to "shape" the region using the alpha channel - of another image (circle.png) and another property to "filter" the region - using the obscure filter. Audio Stuff diff --git a/demo/consumers.ini b/demo/consumers.ini index 5a3d57925..a69e723e8 100644 --- a/demo/consumers.ini +++ b/demo/consumers.ini @@ -1,9 +1,8 @@ -SDL Default sdl -SDL Half D1 sdl:360x288 rescale=nearest resize=1 -SDL High Latency sdl buffer=12 rescale=none -SDL Progressive sdl progressive=1 +SDL Default sdl2 +SDL Half D1 sdl2:360x288 rescale=nearest resize=1 +SDL High Latency sdl2 buffer=12 rescale=none +SDL Progressive sdl2 progressive=1 XML to Terminal xml XML to File xml: -libdv to /dev/dv1394/0 libdv:/dev/dv1394/0 rescale=nearest buffer=25 DeckLink decklink DeckLink Prog LL decklink progressive=1 buffer=1 diff --git a/demo/demo.ini b/demo/demo.ini index a276a6d80..e2394f6f6 100644 --- a/demo/demo.ini +++ b/demo/demo.ini @@ -5,7 +5,6 @@ mlt_my_name_is My name is... clip3.dv mlt_composite_transition A composite transition clip1.dv,clip2.mpeg mlt_fade_in_and_out Fade in and out clip1.dv,clip2.mpeg,clip3.dv mlt_clock_in_and_out Clock in and out clip2.dv,clip1.dv,clip3.mpeg -mlt_obscure Obscure clip2.mpeg,circle.png mlt_audio_stuff Audio Stuff clip*.dv,music1.ogg mlt_levels Audio and Video Levels clip*.dv mlt_titleshadow_watermark Shadowed Title and Watermark clip3.dv @@ -15,7 +14,6 @@ mlt_avantika_title GJ-TTAvantika title pango.mlt mlt_title_over_gfx Title over graphic watermark1.png,clip1.dv mlt_slideshow Slideshow photos mlt_bouncy Bouncy, Bouncy clip1.dv,clip3.dv -mlt_bouncy_ball Bouncy, Bouncy Ball clip1.mpeg,clip3.mpeg,circle.png mlt_news Breaking News clip1.dv,clip2.dv mlt_squeeze Squeeze Transitions clip1.dv,clip2.dv,clip3.dv mlt_squeeze_box Squeeze Box clip1.dv,clip2.dv,clip3.dv @@ -24,7 +22,6 @@ mlt_lcut L Cut clip1.dv,clip2.dv mlt_fade_black Fade from/to black/silence clip3.mpeg mlt_push Push wipe clip1.mpeg, clip2.mpeg mlt_ticker Ticker tape clip1.dv -mlt_attributes Attributes clip1.dv mlt_slideshow_black Composite slideshow photos mlt_slideshow2 Ken Burns slideshow photos mlt_pango_keyframes Pango Keyframed Markup pango_keyframes.mpl diff --git a/demo/mlt_attributes b/demo/mlt_attributes deleted file mode 100644 index 570b194a5..000000000 --- a/demo/mlt_attributes +++ /dev/null @@ -1,7 +0,0 @@ -melt clip1.dv \ -meta.attr.location=1 meta.attr.location.markup="Location" \ -meta.attr.exclusive=1 meta.attr.exclusive.markup="Exclusive" \ -meta.attr.special=1 meta.attr.special.markup="Special" \ -meta.attr.super=1 meta.attr.super.0="Line 1" meta.attr.super.1="Line 2" \ --filter data_show:%etv.properties \ -$* diff --git a/demo/mlt_bouncy b/demo/mlt_bouncy index 9cccc3afa..460507edf 100644 --- a/demo/mlt_bouncy +++ b/demo/mlt_bouncy @@ -2,10 +2,7 @@ melt \ clip3.dv \ -filter \ watermark:clip1.dv \ -composite.start=10%/10%:20%x20% \ -composite.key[33]=30%/70%:25%x25% \ -composite.key[66]=70%/30%:15%x15% \ -composite.end=70%/70%:20%x20% \ +composite.geometry="0=10%/10%:20%x20%; 33=30%/70%:25%x25%; 66=70%/30%:15%x15%; -1=70%/70%:20%x20%" \ composite.out=100 \ composite.sliced_composite=1 \ $* diff --git a/demo/mlt_bouncy_ball b/demo/mlt_bouncy_ball deleted file mode 100644 index e549862a6..000000000 --- a/demo/mlt_bouncy_ball +++ /dev/null @@ -1,15 +0,0 @@ -melt \ -clip3.dv \ --track \ -clip1.dv \ --transition \ -region:circle \ -composite.geometry="10%,10%:20%x20%;33=30%/70%:25%x25%;66=70%/30%:15%x15%;-1=70%/70%:20%x20%" \ -composite.out=100 \ -composite.softness=0.1 \ -composite.sliced_composite=1 \ -a_track=0 \ -b_track=1 \ -in=0 \ -out=5000 \ -$* diff --git a/demo/mlt_composite_transition b/demo/mlt_composite_transition index d6e90b5f4..6a24f9b42 100644 --- a/demo/mlt_composite_transition +++ b/demo/mlt_composite_transition @@ -2,6 +2,6 @@ melt \ clip1.dv out=74 \ -track \ -blank 49 clip2.mpeg \ --transition composite:57%/10%:33%x33% end=0%/0%:100%x100% progressive=1 distort=true in=50 out=74 a_track=0 b_track=1 sliced_composite=1 \ +-transition composite:"0=57%/10%:33%x33%; -1=0%/0%:100%x100%" progressive=1 distort=true in=50 out=74 a_track=0 b_track=1 sliced_composite=1 \ -transition mix:-1 in=50 out=74 a_track=0 b_track=1 \ $* diff --git a/demo/mlt_my_name_is b/demo/mlt_my_name_is index fa4552460..41a799d35 100644 --- a/demo/mlt_my_name_is +++ b/demo/mlt_my_name_is @@ -4,7 +4,7 @@ clip3.dv \ "+My name is Inigo Montoya.txt" out=99 -blank 49 "+Prepare to die!.txt" out=99 \ -track \ -blank 74 "+You killed my father.txt" out=74 \ --transition composite:50%/20%:5%x4% end=10%/20%:80%x12% distort=1 halign=centre valign=centre in=0 out=99 a_track=0 b_track=1 sliced_composite=1 \ --transition composite:0%/70%:100%x10% end=100%/70%:100%x10% in=75 out=149 a_track=0 b_track=2 sliced_composite=1 \ --transition composite:25%/25%:50%x50%! in=150 out=249 a_track=0 b_track=1 sliced_composite=1 \ +-transition composite:"0=50%/20%:5%x4%; -1=10%/20%:80%x12%" distort=1 halign=centre valign=centre in=0 out=99 a_track=0 b_track=1 sliced_composite=1 \ +-transition composite:"0=0%/70%:100%x10%; -1=100%/70%:100%x10%" in=75 out=149 a_track=0 b_track=2 sliced_composite=1 \ +-transition composite:25%/25%:50%x50% in=150 out=249 a_track=0 b_track=1 sliced_composite=1 \ $* diff --git a/demo/mlt_news b/demo/mlt_news index 12074c3a5..303d8aa5c 100644 --- a/demo/mlt_news +++ b/demo/mlt_news @@ -12,7 +12,7 @@ pango: text=" Breaking News -transition mix:0.5 always_active=1 a_track=0 b_track=2 \ -transition composite geometry=50%/15%:37.5%x40% a_track=0 b_track=1 in=0 out=174 sliced_composite=1 \ -transition composite geometry=10%/15%:37.5%x40% a_track=0 b_track=2 in=0 out=199 sliced_composite=1 \ --transition composite geometry="50%/15%:37.5%x40%;-1=0%/0%:100%x100%" a_track=0 b_track=1 in=175 out=199 distort=1 sliced_composite=1 \ +-transition composite geometry="50%/15%:37.5%x40%; -1=0%/0%:100%x100%" a_track=0 b_track=1 in=175 out=199 distort=1 sliced_composite=1 \ -transition composite geometry=10%/65%:90%x20% a_track=0 b_track=3 in=0 out=199 sliced_composite=1 \ -transition composite geometry=10%/65%:90%x20% a_track=1 b_track=3 in=200 out=499 sliced_composite=1 \ $* diff --git a/demo/mlt_obscure b/demo/mlt_obscure deleted file mode 100644 index 1bd3e1261..000000000 --- a/demo/mlt_obscure +++ /dev/null @@ -1,5 +0,0 @@ -melt \ -clip2.mpeg \ --filter obscure:25%/25%:25%x25%:10x10 in=0 out=68 \ --filter region:circle.png filter=obscure composite.start=55%/25%:12%x50% in=68 out=200 region.composite.sliced_composite=1 \ -$* diff --git a/demo/mlt_push b/demo/mlt_push index e1708d9e0..86b8e81f1 100644 --- a/demo/mlt_push +++ b/demo/mlt_push @@ -7,13 +7,11 @@ clip3.dv in=200 out=275 \ clip2.dv in=200 \ -transition \ composite in=50 out=75 a_track=0 b_track=1 \ -start=0/0:100%x100%:100 \ -end=100%/0:100%x100%:100 \ +geometry="0=0/0:100%x100%:100%; -1=100%/0:100%x100%:100%" \ sliced_composite=1 \ -transition \ composite in=50 out=75 a_track=0 b_track=2 \ -start=-100%/0:100%x100%:100 \ -end=0/0:100%x100%:100 \ +geometry="0=-100%/0:100%x100%:100%; -1=0/0:100%x100%:100%" \ sliced_composite=1 \ -transition \ mix:-1 in=50 out=75 a_track=1 b_track=2 \ diff --git a/demo/mlt_slideshow_black b/demo/mlt_slideshow_black index cc1f18680..6cefde3c3 100644 --- a/demo/mlt_slideshow_black +++ b/demo/mlt_slideshow_black @@ -1,3 +1,3 @@ melt photos/.all.jpg ttl=100 \ --filter watermark:colour:black reverse=1 composite.geometry="15%/15%:10%/10%;0.1625=0/0:100%x100%;-.1625=;-1=70%/70%:10%x10%" composite.mirror_off=1 composite.cycle=100 composite.fill=1 composite.valign=c composite.halign=c \ +-filter watermark:colour:black reverse=1 composite.geometry="0=15%/15%:10%/10%; 0.1625=0/0:100%x100%; -.1625=; -1=70%/70%:10%x10%" composite.mirror_off=1 composite.cycle=100 composite.fill=1 composite.valign=c composite.halign=c \ $* diff --git a/demo/mlt_squeeze_box b/demo/mlt_squeeze_box index 5f23fa389..234c74bb6 100644 --- a/demo/mlt_squeeze_box +++ b/demo/mlt_squeeze_box @@ -3,7 +3,7 @@ clip1.dv out=124 clip2.dv out=149 clip3.dv in=75 out=224 clip1.dv \ -track \ -blank 99 colour:black out=49 -blank 99 colour:black out=49 -blank 99 colour:black out=49 \ -group progressive=1 \ --transition composite:0%/0%:100%x100% key[25]=50%/0%:5%x100% end=0%/0%:100%x100% a_track=1 b_track=0 in=100 out=149 sliced_composite=1 \ --transition composite:0%/0%:100%x100% key[25]=0%/50%:100%x5% end=0%/0%:100%x100% a_track=1 b_track=0 in=250 out=299 sliced_composite=1 \ --transition composite:0%/0%:100%x100% key[25]=100%/0%:5%x100% end=0%/0%:100%x100% a_track=1 b_track=0 in=400 out=449 sliced_composite=1 \ +-transition composite:"0=0%/0%:100%x100%; 25=50%/0%:5%x100%; -1=0%/0%:100%x100%" a_track=1 b_track=0 in=100 out=149 sliced_composite=1 \ +-transition composite:"0=0%/0%:100%x100%; 25=0%/50%:100%x5%; -1=0%/0%:100%x100%" a_track=1 b_track=0 in=250 out=299 sliced_composite=1 \ +-transition composite:"0=0%/0%:100%x100%; 25=100%/0%:5%x100%; -1=0%/0%:100%x100%" a_track=1 b_track=0 in=400 out=449 sliced_composite=1 \ $* diff --git a/demo/mlt_ticker b/demo/mlt_ticker index 413c43661..c0afc068b 100644 --- a/demo/mlt_ticker +++ b/demo/mlt_ticker @@ -7,11 +7,10 @@ colour:0 out=299 \ out=299 \ -transition \ composite a_track=0 b_track=1 out=299 distort=1 \ -start=0/70%:100%x64:100 \ +geometry=0/70%:100%x11%:100% \ sliced_composite=1 \ -transition \ composite a_track=0 b_track=2 out=299 titles=1 \ -start=100%/70%:999%x20% \ -end=-299%/70%:999%x20% \ +geometry="0=100%/70%:999%x20%; -1=-299%/70%:999%x20%" \ sliced_composite=1 \ $* diff --git a/demo/mlt_title_over_gfx b/demo/mlt_title_over_gfx index 5b96628bb..f988ccea3 100644 --- a/demo/mlt_title_over_gfx +++ b/demo/mlt_title_over_gfx @@ -5,7 +5,7 @@ melt \ -track \ clip1.dv \ -transition \ - composite start=30%/20%:40%x60% \ + composite:30%/20%:40%x60% \ in=50 \ out=199 \ a_track=0 \ @@ -13,15 +13,12 @@ melt \ distort=1 \ sliced_composite=1 \ -transition \ - composite:0%/75%:100%x20%:0 \ + composite:"0=0%/75%:100%x20%:0; 24=0%/75%:100%x20%:100%; -25=0%/75%:100%x20%:100%; -1=0%/75%:100%x20%:0" \ in=50 \ out=199 \ a_track=2 \ b_track=0 \ - key[24]=0%/75%:100%x20%:100 \ - key[-25]=0%/75%:100%x20%:100 \ luma=luma1.pgm \ - end=0%/75%:100%x20%:0 \ distort=1 \ sliced_composite=1 \ $* diff --git a/demo/mlt_titleshadow_watermark b/demo/mlt_titleshadow_watermark index b137a535e..afe42f663 100644 --- a/demo/mlt_titleshadow_watermark +++ b/demo/mlt_titleshadow_watermark @@ -4,7 +4,7 @@ melt \ -track watermark1.png out=1000 \ -track clip3.dv \ -filter greyscale track=2 \ --transition composite:21%/11%:100%x100%:50 end=61%/41%:100%x100% out=99 a_track=3 b_track=1 sliced_composite=1 \ --transition composite:20%/10%:100%x100% end=60%/40%:100%x100% out=99 a_track=3 b_track=0 sliced_composite=1 \ +-transition composite:"0=21%/11%:100%x100%:50; -1=61%/41%:100%x100%" out=99 a_track=3 b_track=1 sliced_composite=1 \ +-transition composite:"0=20%/10%:100%x100%; -1=60%/40%:100%x100%" out=99 a_track=3 b_track=0 sliced_composite=1 \ -transition composite:85%/80%:10%x10%:30 out=1000 a_track=3 b_track=2 sliced_composite=1 \ $* diff --git a/docs/framework.txt b/docs/framework.txt index 32c9b56bb..5f147fd2e 100644 --- a/docs/framework.txt +++ b/docs/framework.txt @@ -79,14 +79,8 @@ Structure and Flow: +--------+ +--------+ A typical consumer requests MLT Frame objects from the producer, does - something with them and when finished with a frame, closes it. - - /\ A common confusion with the producer/consumer terminology used here is - /!!\ that a consumer may 'produce' something. For example, the libdv consumer - \!!/ produces DV and the libdv producer seems to consume DV. However, the - \/ naming conventions refer only to producers and consumers of MLT Frames. - - To put it another way - a producer produces MLT Frame objects and a consumer + something with them and when finished with a frame, closes it. To put it + another way - a producer produces MLT Frame objects and a consumer consumes MLT Frame objects. An MLT Frame essentially provides an uncompressed image and its associated @@ -213,11 +207,6 @@ Hello World: This will play the video using the avformat producer directly, thus it will bypass the normalising functions. - $ MLT_CONSUMER=libdv ./hello file.avi > /dev/dv1394 - - This might, if you're lucky, do on the fly, realtime conversions of file.avi - to DV and broadcast it to your DV device. - Factories: @@ -1145,7 +1134,6 @@ mlt_frame: mlt_position mlt_frame_get_position( mlt_frame this ); int mlt_frame_set_position( mlt_frame this, mlt_position value ); int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ); - uint8_t *mlt_frame_get_alpha_mask( mlt_frame this ); int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ); int mlt_frame_push_get_image( mlt_frame this, mlt_get_image get_image ); mlt_get_image mlt_frame_pop_get_image( mlt_frame this ); diff --git a/docs/install.txt b/docs/install.txt index 2352ef76d..ebbd8e245 100644 --- a/docs/install.txt +++ b/docs/install.txt @@ -23,19 +23,16 @@ Last Revision: 2013-09-07 * avsync - services to help test audio/video synchronization * core - independent MLT services * decklink - Blackmagick Design SDI/HDMI services - * dv - libdv dependent services (deprecated) - * feeds - templates for use with core's data filters (deprecated) * frei0r - adapter for frei0r video plugins * gdk - GDK pango and pixbuf dependent services * jackrack - adapter for LADSPA audio plugins and JACK server * kdenlive - services contributed by Kdenlive project - * kino - DV/AVI demuxer from Kino project (*)(deprecated) - * linsys - DVEO SDI card consumer (*)(deprecated) - * lumas - wipe file generator for core's luma transition (deprecated) - * motion_est - motion estimation-based filters (*)(deprecated) - * ndi - NewTek NDI producer and consumer * normalize - audio normalisation functions (*) * oldfilm - filters to make pristine video dirty + * movit - Movit dependent services (*) + * ndi - NewTek NDI producer and consumer + * normalize - audio normalization functions (*) + * oldfilm - filters to make pristine video dirty * opencv - OpenCV dependent services * opengl - OpenGL dependent services (*) * plus - miscellaneous services (mixed copyright with no dependencies) @@ -47,10 +44,7 @@ Last Revision: 2013-09-07 * sdl - SDL dependent services * sdl2 - SDL2 dependent services * sox - SoX dependent audio filters - * swfdec - Swfdec dependent producer for Flash files (deprecated) - * videostab - video stabilization filters (*)(deprecated) * vid.stab - video stabilization filters (*) - * vmfx - services contributed by (defunct) Visual Media FX * vorbis - vorbis dependenent services * xine - Xine-derived sources (*) * xml - XML (de)serialization services @@ -78,15 +72,12 @@ Last Revision: 2013-09-07 | *Module* | *Description* | | avformat | [[http://www.ffmpeg.org][FFmpeg]] v4.0 or later | - | dv | [[http://libdv.sf.net][libdv]] 0.102 or later | - | gtk2 | [[http://www.gtk.org][GTK2]] and associated dependencies | | jackrack | [[http://jackaudio.org][JACK]], [[http://www.xmlsoft.org/][libxml2]], and ladspa.h | - | opengl | [[http://git.sesse.net/movit][Movit]] | + | movit | [[http://git.sesse.net/movit][Movit]] | | qt | [[http://www.qt-project.org][Qt]] 4.4 or later | | resample | [[http://www.mega-nerd.com/SRC][libsamplerate]] 0.15 or later | | sdl | [[http://www.libsdl.org][SDL]] 1.2 or later | | sox | [[http://sox.sourceforge.net][SoX]] 13 or later | - | swfdec | [[http://github.com/mltframework/swfdec][swfdec]] 0.8 or later | | vorbis | [[http://www.vorbis.com][libvorbis]] 1.0.1 or later | | xml | [[http://www.xmlsoft.org][libxml2]] 2.5 or later | diff --git a/docs/melt.1 b/docs/melt.1 index 8c5191dc6..d758e1353 100644 --- a/docs/melt.1 +++ b/docs/melt.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.4. -.TH MELT "1" "April 2021" "melt 6.26.1" "User Commands" +.TH MELT "1" "April 2021" "melt 7.0.0" "User Commands" .SH NAME melt \- author, play, and encode multitrack audio/video compositions .SH SYNOPSIS @@ -24,6 +24,9 @@ Add an audio\-only track \fB\-blank\fR frames Add blank silence to a track .TP +\fB\-chain\fR id[:arg] [name=value]* +Add a producer as a chain +.TP \fB\-consumer\fR id[:arg] [name=value]* Set the consumer (sink) .TP @@ -33,6 +36,9 @@ Set the logging level to debug \fB\-filter\fR filter[:arg] [name=value]* Add a filter to the current track .TP +\fB\-getc\fR +Get keyboard input using getc +.TP \fB\-group\fR [name=value]* Apply properties repeatedly .TP @@ -45,6 +51,9 @@ Enable JACK transport synchronization \fB\-join\fR clips Join multiple clips into one cut .TP +\fB\-link\fR id[:arg] [name=value]* +Add a link to a chain +.TP \fB\-mix\fR length Add a mix between the last two cuts .TP @@ -91,7 +100,7 @@ List audio codecs List video codecs .TP \fB\-quiet\fR -Set the logging level to quiet and do not display position/transport +Set the logging level to quiet .TP \fB\-remove\fR Remove the most recent cut @@ -100,7 +109,7 @@ Remove the most recent cut Repeat the last cut .TP \fB\-repository\fR path -Set the directory of MLT plugins +Set the directory of MLT modules .TP \fB\-serialise\fR [filename] Write the commands to a text file @@ -123,6 +132,9 @@ Add a transition \fB\-verbose\fR Set the logging level to verbose .TP +\fB\-timings\fR +Set the logging level to timings +.TP \fB\-version\fR Show the version and copyright .TP diff --git a/docs/melt.txt b/docs/melt.txt index 3805dca8d..4e2c86cf7 100644 --- a/docs/melt.txt +++ b/docs/melt.txt @@ -83,8 +83,8 @@ General rules: Terminology: 'Producers' typically refer to files but may also indicate devices (such as - dv1394 input or video4linux). Hence, the more generic term is used [the more - generic usage is out of scope for now...]. + video4linux). Hence, the more generic term is used [the more generic usage + is out of scope for now...]. 'Filters' are frame modifiers - they always guarantee that for every frame they receive, they output *precisely* one frame. Never more, never less, diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt index 4898916fc..07e8130cc 100644 --- a/src/examples/CMakeLists.txt +++ b/src/examples/CMakeLists.txt @@ -2,8 +2,15 @@ cmake_minimum_required(VERSION 3.14) project(MLT-examples) -find_package(PkgConfig REQUIRED) -pkg_check_modules(mlt++ REQUIRED IMPORTED_TARGET mlt++) +option(WITH_PKGCONFIG "Use pkg-config to find MLT" OFF) add_executable(play play.cpp) -target_link_libraries(play PRIVATE PkgConfig::mlt++) + +if(WITH_PKGCONFIG) + find_package(PkgConfig REQUIRED) + pkg_check_modules(mlt++ REQUIRED IMPORTED_TARGET mlt++-7) + target_link_libraries(play PRIVATE PkgConfig::mlt++) +else() + find_package(Mlt7 REQUIRED COMPONENTS avformat sdl) + target_link_libraries(play PRIVATE Mlt7::mlt++) +endif() diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 6b41d0a61..91e32d45d 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -1,7 +1,43 @@ +set(MLT_PUPLIC_HEADERS + mlt.h + mlt_animation.h + mlt_audio.h + mlt_cache.h + mlt_chain.h + mlt_consumer.h + mlt_deque.h + mlt_events.h + mlt_factory.h + mlt_field.h + mlt_filter.h + mlt_frame.h + mlt_image.h + mlt_link.h + mlt_log.h + mlt_luma_map.h + mlt_multitrack.h + mlt_parser.h + mlt_playlist.h + mlt_pool.h + mlt_producer.h + mlt_profile.h + mlt_properties.h + mlt_property.h + mlt_repository.h + mlt_service.h + mlt_slices.h + mlt_tokeniser.h + mlt_tractor.h + mlt_transition.h + mlt_types.h + mlt_version.h +) + add_library(mlt SHARED mlt_animation.c mlt_audio.c mlt_cache.c + mlt_chain.c mlt_consumer.c mlt_deque.c mlt_events.c @@ -9,7 +45,8 @@ add_library(mlt SHARED mlt_field.c mlt_filter.c mlt_frame.c - mlt_geometry.c + mlt_image.c + mlt_link.c mlt_log.c mlt_luma_map.c mlt_multitrack.c @@ -29,76 +66,63 @@ add_library(mlt SHARED mlt_version.c ) -target_link_libraries(mlt m Threads::Threads ${CMAKE_DL_LIBS}) +add_library(Mlt${MLT_VERSION_MAJOR}::mlt ALIAS mlt) + +target_compile_options(mlt PRIVATE ${MLT_COMPILE_OPTIONS}) + +target_link_libraries(mlt PRIVATE m Threads::Threads ${CMAKE_DL_LIBS}) target_include_directories(mlt PUBLIC $ - $ + $ ) -set_target_properties(mlt PROPERTIES SOVERSION ${MLT_VERSION_MAJOR} VERSION ${MLT_VERSION}) +set_target_properties(mlt PROPERTIES + VERSION ${MLT_VERSION} + SOVERSION ${MLT_VERSION_MAJOR} + OUTPUT_NAME mlt-${MLT_VERSION_MAJOR} + PUBLIC_HEADER "${MLT_PUPLIC_HEADERS}" +) if(WIN32) - set_target_properties(mlt PROPERTIES OUTPUT_NAME "mlt-${MLT_VERSION_MAJOR}") + if(MINGW) + install(FILES "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libmlt-${MLT_VERSION_MAJOR}.dll" + DESTINATION ${CMAKE_INSTALL_LIBDIR} + RENAME libmlt.dll + ) + target_link_options(mlt PRIVATE -Wl,--output-def,libmlt.def) + install(FILES "${CMAKE_BINARY_DIR}/libmlt.def" DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() target_sources(mlt PRIVATE ../win32/win32.c ../win32/strptime.c) - target_link_libraries(mlt Iconv::Iconv) - if(NODEPLOY) + target_link_libraries(mlt PRIVATE Iconv::Iconv) + if(NOT WINDOWS_DEPLOY) target_compile_definitions(mlt PRIVATE NODEPLOY) endif() endif() -if(NOT (WIN32 OR APPLE)) +if(NOT (WIN32 OR (APPLE AND RELOCATABLE))) target_compile_definitions(mlt PRIVATE - PREFIX_DATA="${CMAKE_INSTALL_FULL_DATADIR}/mlt" - PREFIX_LIB="${CMAKE_INSTALL_FULL_LIBDIR}/mlt") + $ + $ + ) + target_link_options(mlt PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/mlt.vers) + set_target_properties(mlt PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/mlt.vers) +elseif(APPLE AND RELOCATABLE) + target_compile_definitions(mlt PRIVATE RELOCATABLE) endif() -set(MLT_PUPLIC_HEADERS - mlt.h - mlt_animation.h - mlt_audio.h - mlt_cache.h - mlt_consumer.h - mlt_deque.h - mlt_events.h - mlt_factory.h - mlt_field.h - mlt_filter.h - mlt_frame.h - mlt_geometry.h - mlt_log.h - mlt_luma_map.h - mlt_multitrack.h - mlt_parser.h - mlt_playlist.h - mlt_pool.h - mlt_producer.h - mlt_profile.h - mlt_properties.h - mlt_property.h - mlt_repository.h - mlt_service.h - mlt_slices.h - mlt_tokeniser.h - mlt_tractor.h - mlt_transition.h - mlt_types.h - mlt_version.h -) - -set_target_properties(mlt PROPERTIES PUBLIC_HEADER "${MLT_PUPLIC_HEADERS}") - install(TARGETS mlt + EXPORT MltTargets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mlt/framework + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mlt-${MLT_VERSION_MAJOR}/framework ) -install(FILES metaschema.yaml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt) +install(FILES metaschema.yaml DESTINATION ${MLT_INSTALL_DATA_DIR}) -configure_file(mlt-framework.pc.in mlt-framework.pc @ONLY) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mlt-framework.pc +configure_file(mlt-framework.pc.in mlt-framework-${MLT_VERSION_MAJOR}.pc @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mlt-framework-${MLT_VERSION_MAJOR}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT Development ) diff --git a/src/framework/Makefile b/src/framework/Makefile index bd7cab541..0f812f53d 100644 --- a/src/framework/Makefile +++ b/src/framework/Makefile @@ -25,9 +25,9 @@ SHFLAGS += -Wl,--version-script=mlt.vers endif OBJS = mlt_audio.o \ + mlt_image.o \ mlt_frame.o \ mlt_version.o \ - mlt_geometry.o \ mlt_deque.o \ mlt_property.o \ mlt_properties.o \ @@ -51,9 +51,12 @@ OBJS = mlt_audio.o \ mlt_cache.o \ mlt_animation.o \ mlt_slices.o \ - mlt_luma_map.o + mlt_luma_map.o \ + mlt_link.o \ + mlt_chain.o INCS = mlt_audio.h \ + mlt_image.h \ mlt_consumer.h \ mlt_version.h \ mlt_factory.h \ @@ -70,7 +73,6 @@ INCS = mlt_audio.h \ mlt_deque.h \ mlt_field.h \ mlt_frame.h \ - mlt_geometry.h \ mlt_playlist.h \ mlt_producer.h \ mlt_property.h \ @@ -82,7 +84,9 @@ INCS = mlt_audio.h \ mlt_cache.h \ mlt_animation.h \ mlt_slices.h \ - mlt_luma_map.h + mlt_luma_map.h \ + mlt_link.h \ + mlt_chain.h SRCS := $(OBJS:.o=.c) diff --git a/src/framework/metaschema.yaml b/src/framework/metaschema.yaml index 91e05e987..5d9820273 100644 --- a/src/framework/metaschema.yaml +++ b/src/framework/metaschema.yaml @@ -1,5 +1,5 @@ --- # A metadata schema in Kwalify: http://www.kuwata-lab.com/kwalify/ -# Version: 0.3 +# Version: 7.0 type: map mapping: "schema_version": # This should match the version comment above @@ -11,7 +11,7 @@ mapping: "type": # A service type type: str required: yes - enum: [consumer, filter, producer, transition] + enum: [consumer, filter, link, producer, transition] "identifier": # The same value used to register and create the service type: str required: yes @@ -97,6 +97,9 @@ mapping: # processing the first frame type: bool default: no + "animation": # Does the property support the animation API for keyframes? + type: bool + default: no "widget": # A hint to the UI about how to let the user set this type: str enum: diff --git a/src/framework/mlt-framework.pc.in b/src/framework/mlt-framework.pc.in index 9c15bbc81..a15899a7a 100644 --- a/src/framework/mlt-framework.pc.in +++ b/src/framework/mlt-framework.pc.in @@ -4,12 +4,12 @@ libdir=@CMAKE_INSTALL_FULL_LIBDIR@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ datadir=@CMAKE_INSTALL_FULL_DATADIR@ -moduledir=${libdir}/mlt -mltdatadir=${datadir}/mlt +moduledir=${libdir}/mlt-@MLT_VERSION_MAJOR@ +mltdatadir=${datadir}/mlt-@MLT_VERSION_MAJOR@ Name: mlt-framework Description: MLT multimedia framework Version: @MLT_VERSION@ Requires: -Libs: -L${libdir} -lmlt -Cflags: -I${includedir} -I${includedir}/mlt +Libs: -L${libdir} -lmlt-@MLT_VERSION_MAJOR@ +Cflags: -I${includedir}/mlt-@MLT_VERSION_MAJOR@ diff --git a/src/framework/mlt.h b/src/framework/mlt.h index f4f345ac0..b8575b9a9 100644 --- a/src/framework/mlt.h +++ b/src/framework/mlt.h @@ -2,7 +2,7 @@ * \file mlt.h * \brief header file for lazy client and implementation code :-) * - * Copyright (C) 2003-2017 Meltytech, LLC + * Copyright (C) 2003-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 @@ -40,6 +40,7 @@ extern "C" #include "mlt_audio.h" #include "mlt_factory.h" #include "mlt_frame.h" +#include "mlt_image.h" #include "mlt_deque.h" #include "mlt_multitrack.h" #include "mlt_producer.h" @@ -52,13 +53,14 @@ extern "C" #include "mlt_tractor.h" #include "mlt_tokeniser.h" #include "mlt_parser.h" -#include "mlt_geometry.h" #include "mlt_profile.h" #include "mlt_repository.h" #include "mlt_log.h" #include "mlt_cache.h" #include "mlt_version.h" #include "mlt_slices.h" +#include "mlt_link.h" +#include "mlt_chain.h" #ifdef __cplusplus } diff --git a/src/framework/mlt.vers b/src/framework/mlt.vers index 20b5cb029..732118673 100644 --- a/src/framework/mlt.vers +++ b/src/framework/mlt.vers @@ -576,3 +576,42 @@ MLT_6.22.0 { mlt_audio_channel_layout_channels; mlt_audio_channel_layout_default; } MLT_6.20.0; + +MLT_7.0.0 { + global: + mlt_factory_link; + mlt_chain_init; + mlt_chain_set_source; + mlt_chain_get_source; + mlt_chain_attach; + mlt_chain_detach; + mlt_chain_link_count; + mlt_chain_move_link; + mlt_chain_link; + mlt_chain_close; + mlt_link_init; + mlt_link_connect_next; + mlt_link_close; + mlt_repository_links; + mlt_animation_shift_frames; + mlt_animation_get_string; + mlt_image_new; + mlt_image_close; + mlt_image_set_values; + mlt_image_get_values; + mlt_image_alloc_data; + mlt_image_alloc_alpha; + mlt_image_calculate_size; + mlt_image_fill_black; + mlt_image_fill_opaque; + mlt_audio_silence; + mlt_event_data_none; + mlt_event_data_from_int; + mlt_event_data_to_int; + mlt_event_data_from_string; + mlt_event_data_to_string; + mlt_event_data_from_frame; + mlt_event_data_to_frame; + mlt_event_data_from_object; + mlt_event_data_to_object; +} MLT_6.22.0; diff --git a/src/framework/mlt_animation.c b/src/framework/mlt_animation.c index 18604761a..2dc945f30 100644 --- a/src/framework/mlt_animation.c +++ b/src/framework/mlt_animation.c @@ -3,7 +3,7 @@ * \brief Property Animation class definition * \see mlt_animation_s * - * Copyright (C) 2004-2018 Meltytech, LLC + * Copyright (C) 2004-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 @@ -54,6 +54,8 @@ struct mlt_animation_s animation_node nodes; /**< a linked list of keyframes (and possibly non-keyframe values) */ }; +static void mlt_animation_clear_string( mlt_animation self ); + /** Create a new animation object. * * \public \memberof mlt_animation_s @@ -301,8 +303,10 @@ int mlt_animation_get_length( mlt_animation self ) void mlt_animation_set_length( mlt_animation self, int length ) { - if ( self ) + if ( self ) { self->length = length; + mlt_animation_clear_string( self ); + } } /** Parse a string representing an animation keyframe=value. @@ -473,7 +477,8 @@ int mlt_animation_insert( mlt_animation self, mlt_animation_item item ) node->item.is_key = 1; node->item.keyframe_type = item->keyframe_type; node->item.property = mlt_property_init(); - mlt_property_pass( node->item.property, item->property ); + if (item->property) + mlt_property_pass( node->item.property, item->property ); // Determine if we need to insert or append to the list, or if it's a new list if ( self->nodes ) @@ -519,6 +524,7 @@ int mlt_animation_insert( mlt_animation self, mlt_animation_item item ) // Set the first item self->nodes = node; } + mlt_animation_clear_string( self ); return error; } @@ -544,6 +550,8 @@ int mlt_animation_remove( mlt_animation self, int position ) if ( node && position == node->item.frame ) error = mlt_animation_drop( self, node ); + mlt_animation_clear_string( self ); + return error; } @@ -897,6 +905,7 @@ int mlt_animation_key_set_type(mlt_animation self, int index, mlt_keyframe_type if ( node ) { node->item.keyframe_type = type; mlt_animation_interpolate(self); + mlt_animation_clear_string( self ); } else { error = 1; } @@ -928,9 +937,56 @@ int mlt_animation_key_set_frame(mlt_animation self, int index, int frame) if ( node ) { node->item.frame = frame; mlt_animation_interpolate(self); + mlt_animation_clear_string( self ); } else { error = 1; } return error; } + +/** Shift the frame value for all nodes. + * + * \public \memberof mlt_animation_s + * \param self an animation + * \param shift the value to add to all frame values + */ + +void mlt_animation_shift_frames( mlt_animation self, int shift ) +{ + animation_node node = self->nodes; + while ( node ) { + node->item.frame += shift; + node = node->next; + } + mlt_animation_clear_string( self ); + mlt_animation_interpolate(self); +} + +/** Get the cached serialization string. + * + * This can be used to determine if the animation has been modified because the + * string is cleared whenever the animation is changed. + * \public \memberof mlt_animation_s + * \param self an animation + * \return the cached serialization string + */ + +const char* mlt_animation_get_string( mlt_animation self ) +{ + if (!self) return NULL; + return self->data; +} + +/** Clear the cached serialization string. + * + * \private \memberof mlt_animation_s + * \param self an animation + */ + +void mlt_animation_clear_string( mlt_animation self ) +{ + if (!self) return; + free( self->data ); + self->data = NULL; +} diff --git a/src/framework/mlt_animation.h b/src/framework/mlt_animation.h index 48d478ce6..107f63d04 100644 --- a/src/framework/mlt_animation.h +++ b/src/framework/mlt_animation.h @@ -69,6 +69,8 @@ extern int mlt_animation_key_get( mlt_animation self, mlt_animation_item item, i extern void mlt_animation_close( mlt_animation self ); extern int mlt_animation_key_set_type( mlt_animation self, int index, mlt_keyframe_type type ); extern int mlt_animation_key_set_frame( mlt_animation self, int index, int frame ); +extern void mlt_animation_shift_frames( mlt_animation self, int shift ); +extern const char* mlt_animation_get_string( mlt_animation self ); #endif diff --git a/src/framework/mlt_audio.c b/src/framework/mlt_audio.c index 1541977eb..727327b71 100644 --- a/src/framework/mlt_audio.c +++ b/src/framework/mlt_audio.c @@ -208,6 +208,69 @@ void mlt_audio_get_planes( mlt_audio self, uint8_t** planes ) } } +/** Set a range of samples to silence. + * + * \public \memberof mlt_frame_s + * \param self the Audio object + * \param samples the new number of samples to silent + * \param start the sample to begin the silence + * \return none + */ + +void mlt_audio_silence( mlt_audio self, int samples, int start ) +{ + if ( ( start + samples ) > self->samples ) + { + mlt_log_error( NULL, "mlt_audio_silence: avoid buffer overrun\n" ); + return; + } + + switch ( self->format ) + { + case mlt_audio_none: + mlt_log_error( NULL, "mlt_audio_silence: mlt_audio_none\n" ); + return; + // Interleaved 8bit formats + case mlt_audio_u8: + { + int8_t* s = (int8_t*)self->data + ( start * self->channels ); + int size = self->channels * samples * sizeof(int8_t); + memset( s, 127, size ); + return; + } + // Interleaved 16bit formats + case mlt_audio_s16: + { + int16_t* s = (int16_t*)self->data + ( start * self->channels ); + int size = self->channels * samples * sizeof(int16_t); + memset( s, 0, size ); + return; + } + // Interleaved 32bit formats + case mlt_audio_s32le: + case mlt_audio_f32le: + { + int32_t* s = (int32_t*)self->data + ( start * self->channels ); + int size = self->channels * samples * sizeof(int32_t); + memset( s, 0, size ); + return; + } + // Planer 32bit formats + case mlt_audio_s32: + case mlt_audio_float: + { + int p = 0; + for ( p = 0; p < self->channels; p++ ) + { + int32_t* s = (int32_t*)self->data + (p * self->samples) + start; + int size = samples * sizeof(int32_t); + memset( s, 0, size ); + } + return; + } + } +} + /** Shrink the audio to the new number of samples. * * Existing samples will be moved as necessary to ensure that the audio planes @@ -649,63 +712,3 @@ mlt_channel_layout mlt_audio_channel_layout_default( int channels ) } return mlt_channel_independent; } - -/** Determine the number of samples that belong in a frame at a time position. - * - * \deprecated since 6.22. Prefer mlt_audio_calculate_samples() - */ - -int mlt_sample_calculator( float fps, int frequency, int64_t position ) -{ - return mlt_audio_calculate_frame_samples( fps, frequency, position ); -} - -/** Determine the number of samples that belong before a time position. - * - * \deprecated since 6.22. Prefer mlt_audio_calculate_samples_to_position() - */ - -int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position ) -{ - return mlt_audio_calculate_samples_to_position( fps, frequency, position ); -} - -/** Get the short name for a channel layout. - * - * \deprecated since 6.22. Prefer mlt_audio_channel_layout_name() - */ - -const char * mlt_channel_layout_name( mlt_channel_layout layout ) -{ - return mlt_audio_channel_layout_name( layout ); -} - -/** Get the id of channel layout from short name. - * - * \deprecated since 6.22. Prefer mlt_audio_channel_layout_id() - */ - -mlt_channel_layout mlt_channel_layout_id( const char * name ) -{ - return mlt_audio_channel_layout_id( name ); -} - -/** Get the number of channels for a channel layout. - * - * \deprecated since 6.22. Prefer mlt_audio_channel_layout_channels() - */ - -int mlt_channel_layout_channels( mlt_channel_layout layout ) -{ - return mlt_audio_channel_layout_channels( layout ); -} - -/** Get a default channel layout for a given number of channels. - * - * \deprecated since 6.22. Prefer mlt_audio_channel_layout_default() - */ - -mlt_channel_layout mlt_channel_layout_default( int channels ) -{ - return mlt_audio_channel_layout_default( channels ); -} diff --git a/src/framework/mlt_audio.h b/src/framework/mlt_audio.h index 3177e119e..89dc06ffb 100644 --- a/src/framework/mlt_audio.h +++ b/src/framework/mlt_audio.h @@ -51,6 +51,7 @@ extern int mlt_audio_calculate_size( mlt_audio self ); extern int mlt_audio_plane_count( mlt_audio self ); extern int mlt_audio_plane_size( mlt_audio self ); extern void mlt_audio_get_planes( mlt_audio self, uint8_t** planes ); +extern void mlt_audio_silence( mlt_audio self, int samples, int start ); extern void mlt_audio_shrink( mlt_audio self , int samples ); extern void mlt_audio_reverse( mlt_audio self ); extern void mlt_audio_copy( mlt_audio dst, mlt_audio src, int samples, int src_start, int dst_start ); @@ -63,12 +64,4 @@ extern mlt_channel_layout mlt_audio_channel_layout_id( const char * name ); extern int mlt_audio_channel_layout_channels( mlt_channel_layout layout ); extern mlt_channel_layout mlt_audio_channel_layout_default( int channels ); -// Deprecated functions -extern int mlt_sample_calculator( float fps, int frequency, int64_t position ); -extern int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position ); -extern const char * mlt_channel_layout_name( mlt_channel_layout layout ); -extern mlt_channel_layout mlt_channel_layout_id( const char * name ); -extern int mlt_channel_layout_channels( mlt_channel_layout layout ); -extern mlt_channel_layout mlt_channel_layout_default( int channels ); - #endif diff --git a/src/framework/mlt_chain.c b/src/framework/mlt_chain.c new file mode 100644 index 000000000..0d6866fa3 --- /dev/null +++ b/src/framework/mlt_chain.c @@ -0,0 +1,470 @@ +/** + * \file mlt_chain.c + * \brief link service class + * \see mlt_chain_s + * + * Copyright (C) 2020 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 "mlt_chain.h" +#include "mlt_factory.h" +#include "mlt_frame.h" +#include "mlt_log.h" + +#include +#include +#include + +/** \brief private service definition */ + +typedef struct +{ + int link_count; + int link_size; + mlt_link* links; + mlt_producer source; + mlt_profile source_profile; + mlt_properties source_parameters; + mlt_producer begin; +} +mlt_chain_base; + +/* Forward references to static methods. +*/ + +static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); +static void relink_chain( mlt_chain self ); +static void chain_property_changed( mlt_service owner, mlt_chain self, char *name ); +static void source_property_changed( mlt_service owner, mlt_chain self, char *name ); + +/** Construct a chain. + * + * \public \memberof mlt_chain_s + * \return the new chain + */ + +mlt_chain mlt_chain_init( mlt_profile profile ) +{ + mlt_chain self = calloc( 1, sizeof( struct mlt_chain_s ) ); + if ( self != NULL ) + { + mlt_producer producer = &self->parent; + if ( mlt_producer_init( producer, self ) == 0 ) + { + mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); + + mlt_properties_set( properties, "mlt_type", "chain" ); + mlt_properties_clear( properties, "resource"); + mlt_properties_clear( properties, "mlt_service"); + mlt_properties_clear( properties, "in"); + mlt_properties_clear( properties, "out"); + mlt_properties_clear( properties, "length"); + + producer->get_frame = producer_get_frame; + producer->close = ( mlt_destructor )mlt_chain_close; + producer->close_object = self; + + mlt_service_set_profile( MLT_CHAIN_SERVICE( self ), profile ); + + // Generate local space + self->local = calloc( 1, sizeof( mlt_chain_base ) ); + mlt_chain_base* base = self->local; + base->source_profile = mlt_profile_init(NULL); + + // Listen to property changes to pass along to the source + mlt_events_listen( MLT_CHAIN_PROPERTIES(self), self, "property-changed", ( mlt_listener )chain_property_changed ); + } + else + { + free( self ); + self = NULL; + } + } + return self; +} + +/** Set the source producer. + * + * \public \memberof mlt_chain_s + * \param self a chain + * \param source the new source producer + */ + +void mlt_chain_set_source( mlt_chain self, mlt_producer source ) +{ + int error = self == NULL || source == NULL; + if ( error == 0 ) + { + mlt_chain_base* base = self->local; + mlt_properties source_properties = MLT_PRODUCER_PROPERTIES( source ); + int n = 0; + int i = 0; + + // Clean up from previous source + mlt_producer_close( base->source ); + mlt_properties_close( base->source_parameters ); + + // Save the source producer + base->source = source; + mlt_properties_inc_ref( source_properties ); + + // Create a list of all parameters used by the source producer so that + // they can be passed between the source producer and this chain. + base->source_parameters = mlt_properties_new(); + mlt_repository repository = mlt_factory_repository(); + char* source_metadata_name = strdup( mlt_properties_get( source_properties, "mlt_service" ) ); + // If the service name ends in "-novalidate", then drop the ending and search for the metadata of the main service. + // E.g. "avformat-novalidate" -> "avformat" + char* novalidate_ptr = strstr(source_metadata_name, "-novalidate"); + if ( novalidate_ptr ) *novalidate_ptr = '\0'; + mlt_properties source_metadata = mlt_repository_metadata( repository, mlt_service_producer_type, source_metadata_name ); + free( source_metadata_name ); + if ( source_metadata ) + { + mlt_properties params = (mlt_properties) mlt_properties_get_data( source_metadata, "parameters", NULL ); + if ( params ) + { + n = mlt_properties_count( params ); + for ( i = 0; i < n; i++ ) + { + mlt_properties param = (mlt_properties) mlt_properties_get_data( params, mlt_properties_get_name( params, i ), NULL ); + char* identifier = mlt_properties_get( param, "identifier" ); + if ( identifier ) + { + // Set the value to 1 to indicate the parameter exists. + mlt_properties_set_int( base->source_parameters, identifier, 1 ); + } + } + } + } + + // Pass parameters and properties from the source producer to this chain. + // Some properties may have been set during source initialization. + n = mlt_properties_count( source_properties ); + mlt_events_block( MLT_CHAIN_PROPERTIES(self), self ); + for ( i = 0; i < n; i++ ) + { + char* name = mlt_properties_get_name( source_properties, i ); + if ( mlt_properties_get_int( base->source_parameters, name ) || + !strcmp( name, "mlt_service" ) || + !strcmp( name, "_mlt_service_hidden" ) || + !strcmp( name, "seekable" ) || + !strncmp( name, "meta.", 5 ) ) + { + mlt_properties_pass_property( MLT_CHAIN_PROPERTIES(self), source_properties, name ); + } + } + // If a length has not been specified for this chain, copy in/out/length from the source producer + if ( !mlt_producer_get_length( MLT_CHAIN_PRODUCER(self) ) ) { + mlt_properties_set_position( MLT_CHAIN_PROPERTIES(self), "length", mlt_producer_get_length( base->source ) ); + mlt_producer_set_in_and_out( MLT_CHAIN_PRODUCER(self), mlt_producer_get_in( base->source ), mlt_producer_get_out( base->source ) ); + } + mlt_events_unblock( MLT_CHAIN_PROPERTIES(self), self ); + + // Monitor property changes from the source to pass to the chain. + mlt_events_listen( source_properties, self, "property-changed", ( mlt_listener )source_property_changed ); + + // Save the native source producer profile + mlt_profile_from_producer( base->source_profile, base->source ); + + // This chain will control the speed and in/out + mlt_producer_set_speed( base->source, 0.0 ); + // Approximate infinite length + mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( base->source ), "length", 0x7fffffff ); + mlt_producer_set_in_and_out( base->source, 0, mlt_producer_get_length( base->source ) - 1 ); + + // Reconfigure the chain + relink_chain( self ); + mlt_events_fire( MLT_CHAIN_PROPERTIES(self), "chain-changed", mlt_event_data_none() ); + } +} + +/** Get the source producer. + * + * \public \memberof mlt_chain_s + * \param self a chain + * \return the source producer + */ + +extern mlt_producer mlt_chain_get_source( mlt_chain self ) +{ + mlt_producer source = NULL; + if ( self && self->local ) + { + mlt_chain_base* base = self->local; + source = base->source; + } + return source; +} + +/** Attach a link. + * + * \public \memberof mlt_chain_s + * \param self a chain + * \param link the link to attach + * \return true if there was an error + */ + +int mlt_chain_attach( mlt_chain self, mlt_link link ) +{ + int error = self == NULL || link == NULL; + if ( error == 0 ) + { + int i = 0; + mlt_chain_base *base = self->local; + + for ( i = 0; error == 0 && i < base->link_count; i ++ ) + if ( base->links[ i ] == link ) + error = 1; + + if ( error == 0 ) + { + if ( base->link_count == base->link_size ) + { + base->link_size += 10; + base->links = realloc( base->links, base->link_size * sizeof( mlt_link ) ); + } + + if ( base->links != NULL ) + { + mlt_properties_inc_ref( MLT_LINK_PROPERTIES( link ) ); + mlt_properties_set_data( MLT_LINK_PROPERTIES( link ), "chain", self, 0, NULL, NULL ); + base->links[ base->link_count ++ ] = link; + relink_chain( self ); + mlt_events_fire( MLT_CHAIN_PROPERTIES(self), "chain-changed", mlt_event_data_none() ); + } + else + { + error = 2; + } + } + } + return error; +} + +/** Detach a link. + * + * \public \memberof mlt_chain_s + * \param self a chain + * \param link the link to detach + * \return true if there was an error + */ + +int mlt_chain_detach( mlt_chain self, mlt_link link ) +{ + int error = self == NULL || link == NULL; + if ( error == 0 ) + { + int i = 0; + mlt_chain_base *base = self->local; + + for ( i = 0; i < base->link_count; i ++ ) + if ( base->links[ i ] == link ) + break; + + if ( i < base->link_count ) + { + base->links[ i ] = NULL; + for ( i ++ ; i < base->link_count; i ++ ) + base->links[ i - 1 ] = base->links[ i ]; + base->link_count --; + mlt_link_close( link ); + relink_chain( self ); + mlt_events_fire( MLT_CHAIN_PROPERTIES(self), "chain-changed", mlt_event_data_none() ); + } + } + return error; +} + +/** Get the number of links attached. + * + * \public \memberof mlt_chain_s + * \param self a chain + * \return the number of attached links or -1 if there was an error + */ + +int mlt_chain_link_count( mlt_chain self ) +{ + int result = -1; + if ( self ) + { + mlt_chain_base *base = self->local; + result = base->link_count; + } + return result; +} + +/** Reorder the attached links. + * + * \public \memberof mlt_chain_s + * \param self a chain + * \param from the current index value of the link to move + * \param to the new index value for the link specified in \p from + * \return true if there was an error + */ + +int mlt_chain_move_link( mlt_chain self, int from, int to ) +{ + int error = -1; + if ( self ) + { + mlt_chain_base *base = self->local; + if ( from < 0 ) from = 0; + if ( from >= base->link_count ) from = base->link_count - 1; + if ( to < 0 ) to = 0; + if ( to >= base->link_count ) to = base->link_count - 1; + if ( from != to && base->link_count > 1 ) + { + mlt_link link = base->links[from]; + int i; + if ( from > to ) + { + for ( i = from; i > to; i-- ) + base->links[i] = base->links[i - 1]; + } + else + { + for ( i = from; i < to; i++ ) + base->links[i] = base->links[i + 1]; + } + base->links[to] = link; + relink_chain( self ); + mlt_events_fire( MLT_CHAIN_PROPERTIES(self), "chain-changed", mlt_event_data_none() ); + error = 0; + } + } + return error; +} + +/** Retrieve an attached link. + * + * \public \memberof mlt_chain_s + * \param self a chain + * \param index which one of potentially multiple links + * \return the link or null if there was an error + */ + +mlt_link mlt_chain_link( mlt_chain self, int index ) +{ + mlt_link link = NULL; + if ( self != NULL ) + { + mlt_chain_base *base = self->local; + if ( index >= 0 && index < base->link_count ) + link = base->links[ index ]; + } + return link; +} + +/** Close the chain and free its resources. + * + * \public \memberof mlt_chain_s + * \param self a chain + */ + +void mlt_chain_close( mlt_chain self ) +{ + if ( self != NULL && mlt_properties_dec_ref( MLT_CHAIN_PROPERTIES( self ) ) <= 0 ) + { + int i = 0; + mlt_chain_base *base = self->local; + mlt_events_block( MLT_CHAIN_PROPERTIES( self ), self ); + for ( i = 0; i < base->link_count; i ++ ) + mlt_link_close( base->links[ i ] ); + free( base->links ); + mlt_profile_close( base->source_profile ); + free( base ); + self->parent.close = NULL; + mlt_producer_close( &self->parent ); + free( self ); + } +} + +static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ) +{ + int result = 1; + if ( parent && parent->child ) + { + mlt_chain self = parent->child; + if( self ) + { + mlt_chain_base *base = self->local; + mlt_producer_seek( base->begin, mlt_producer_frame( parent ) ); + result = mlt_service_get_frame( MLT_PRODUCER_SERVICE( base->begin ), frame, index ); + mlt_producer_prepare_next( parent ); + } + } + return result; +} + +static void relink_chain( mlt_chain self ) +{ + mlt_chain_base *base = self->local; + mlt_profile profile = mlt_service_profile( MLT_CHAIN_SERVICE(self) ); + + if ( base->link_count == 0 ) + { + base->begin = base->source; + // If there are no links, the producer can operate in the final frame rate + mlt_service_set_profile( MLT_PRODUCER_SERVICE(base->source), profile ); + } + else + { + // Set the producer to be in native frame rate + mlt_service_set_profile( MLT_PRODUCER_SERVICE(base->source), base->source_profile ); + + int i = 0; + base->begin = MLT_LINK_PRODUCER( base->links[0] ); + for ( i = 0; i < base->link_count - 1; i++ ) + { + mlt_link_connect_next( base->links[i], MLT_LINK_PRODUCER( base->links[i+1] ), profile ); + } + mlt_link_connect_next( base->links[base->link_count -1], base->source, profile ); + } +} + +static void chain_property_changed( mlt_service owner, mlt_chain self, char *name ) +{ + mlt_chain_base *base = self->local; + if ( !base->source ) return; + if ( mlt_properties_get_int( base->source_parameters, name ) || + !strncmp( name, "meta.", 5 ) ) + { + // Pass parameter changes from this chain to the encapsulated source producer. + mlt_properties chain_properties = MLT_CHAIN_PROPERTIES( self ); + mlt_properties source_properties = MLT_PRODUCER_PROPERTIES( base->source ); + mlt_events_block( source_properties, self ); + mlt_properties_pass_property( source_properties, chain_properties, name ); + mlt_events_unblock( source_properties, self ); + } +} + +static void source_property_changed( mlt_service owner, mlt_chain self, char *name ) +{ + mlt_chain_base *base = self->local; + if ( mlt_properties_get_int( base->source_parameters, name ) || + !strncmp( name, "meta.", 5 ) ) + { + // The source producer might change its own parameters. + // Pass those changes to this producer. + mlt_properties chain_properties = MLT_CHAIN_PROPERTIES( self ); + mlt_properties source_properties = MLT_PRODUCER_PROPERTIES( base->source ); + mlt_events_block( chain_properties, self ); + mlt_properties_pass_property( chain_properties, source_properties, name ); + mlt_events_unblock( chain_properties, self ); + } +} diff --git a/src/framework/mlt_chain.h b/src/framework/mlt_chain.h new file mode 100644 index 000000000..778b1a8c5 --- /dev/null +++ b/src/framework/mlt_chain.h @@ -0,0 +1,56 @@ +/** + * \file mlt_chain.h + * \brief chain service class + * \see mlt_chain_s + * + * Copyright (C) 2020 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 MLT_CHAIN_H +#define MLT_CHAIN_H + +#include "mlt_link.h" +#include "mlt_producer.h" + +/** \brief Chain class + * + * The chain is a producer class that that can connect multiple link producers in a sequence. + * + * \extends mlt_producer_s + */ + +struct mlt_chain_s +{ + struct mlt_producer_s parent; + void* local; /**< \private instance object */ +}; + +#define MLT_CHAIN_PRODUCER( chain ) ( &( chain )->parent ) +#define MLT_CHAIN_SERVICE( chain ) MLT_PRODUCER_SERVICE( MLT_CHAIN_PRODUCER( chain ) ) +#define MLT_CHAIN_PROPERTIES( chain ) MLT_SERVICE_PROPERTIES( MLT_CHAIN_SERVICE( chain ) ) + +extern mlt_chain mlt_chain_init( mlt_profile ); +extern void mlt_chain_set_source( mlt_chain self, mlt_producer source ); +extern mlt_producer mlt_chain_get_source( mlt_chain self ); +extern int mlt_chain_attach( mlt_chain self, mlt_link link ); +extern int mlt_chain_detach( mlt_chain self, mlt_link link ); +extern int mlt_chain_link_count( mlt_chain self ); +extern int mlt_chain_move_link( mlt_chain self, int from, int to ); +extern mlt_link mlt_chain_link( mlt_chain self, int index ); +extern void mlt_chain_close( mlt_chain self ); + +#endif diff --git a/src/framework/mlt_consumer.c b/src/framework/mlt_consumer.c index 15fb5cb07..43e69bbff 100644 --- a/src/framework/mlt_consumer.c +++ b/src/framework/mlt_consumer.c @@ -3,7 +3,7 @@ * \brief abstraction for all consumer services * \see mlt_consumer_s * - * Copyright (C) 2003-2020 Meltytech, LLC + * Copyright (C) 2003-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 @@ -80,16 +80,10 @@ typedef struct } consumer_private; -typedef void* ( *thread_function_t )( void* ); - -static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ); -static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ); -static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer self, char *name ); +static void mlt_consumer_property_changed(mlt_properties owner, mlt_consumer self, mlt_event_data ); static void apply_profile_properties( mlt_consumer self, mlt_profile profile, mlt_properties properties ); -static void on_consumer_frame_show( mlt_properties owner, mlt_consumer self, mlt_frame frame ); -static void transmit_thread_create( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ); -static void mlt_thread_create( mlt_consumer self, thread_function_t function ); -static void transmit_thread_join( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ); +static void on_consumer_frame_show(mlt_properties owner, mlt_consumer self, mlt_event_data ); +static void mlt_thread_create( mlt_consumer self, mlt_thread_function_t function ); static void mlt_thread_join( mlt_consumer self ); static void consumer_read_ahead_start( mlt_consumer self ); @@ -149,14 +143,14 @@ int mlt_consumer_init( mlt_consumer self, void *child, mlt_profile profile ) priv->image_format = mlt_image_yuv422; priv->audio_format = mlt_audio_s16; - mlt_events_register( properties, "consumer-frame-show", ( mlt_transmitter )mlt_consumer_frame_show ); - mlt_events_register( properties, "consumer-frame-render", ( mlt_transmitter )mlt_consumer_frame_render ); - mlt_events_register( properties, "consumer-thread-started", NULL ); - mlt_events_register( properties, "consumer-thread-stopped", NULL ); - mlt_events_register( properties, "consumer-stopping", NULL ); - mlt_events_register( properties, "consumer-stopped", NULL ); - mlt_events_register( properties, "consumer-thread-create", ( mlt_transmitter )transmit_thread_create ); - mlt_events_register( properties, "consumer-thread-join", ( mlt_transmitter )transmit_thread_join ); + mlt_events_register( properties, "consumer-frame-show" ); + mlt_events_register( properties, "consumer-frame-render" ); + mlt_events_register( properties, "consumer-thread-started" ); + mlt_events_register( properties, "consumer-thread-stopped" ); + mlt_events_register( properties, "consumer-stopping" ); + mlt_events_register( properties, "consumer-stopped" ); + mlt_events_register( properties, "consumer-thread-create" ); + mlt_events_register( properties, "consumer-thread-join" ); mlt_events_listen( properties, self, "consumer-frame-show", ( mlt_listener )on_consumer_frame_show ); // Register a property-changed listener to handle the profile property - @@ -208,9 +202,10 @@ static void apply_profile_properties( mlt_consumer self, mlt_profile profile, ml * \param name the name of the property that changed */ -static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer self, char *name ) +static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer self, mlt_event_data event_data ) { - if ( !strcmp( name, "mlt_profile" ) ) + const char *name = mlt_event_data_to_string(event_data); + if ( name && !strcmp( name, "mlt_profile" ) ) { // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); @@ -330,40 +325,6 @@ static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer se } } -/** The transmitter for the consumer-frame-show event - * - * Invokes the listener. - * - * \private \memberof mlt_consumer_s - * \param listener a function pointer that will be invoked - * \param owner the events object that will be passed to \p listener - * \param self a service that will be passed to \p listener - * \param args an array of pointers - the first entry is passed as a frame to \p listener - */ - -static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) -{ - if ( listener != NULL ) - listener( owner, self, ( mlt_frame )args[ 0 ] ); -} - -/** The transmitter for the consumer-frame-render event - * - * Invokes the listener. - * - * \private \memberof mlt_consumer_s - * \param listener a function pointer that will be invoked - * \param owner the events object that will be passed to \p listener - * \param self a service that will be passed to \p listener - * \param args an array of pointers - the first entry is passed as a frame to \p listener - */ - -static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) -{ - if ( listener != NULL ) - listener( owner, self, ( mlt_frame )args[ 0 ] ); -} - /** A listener on the consumer-frame-show event * * Saves the position of the frame shown. @@ -374,8 +335,9 @@ static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties own * \param frame the frame that was shown */ -static void on_consumer_frame_show( mlt_properties owner, mlt_consumer consumer, mlt_frame frame ) +static void on_consumer_frame_show( mlt_properties owner, mlt_consumer consumer, mlt_event_data event_data ) { + mlt_frame frame = mlt_event_data_to_frame(event_data); if ( frame ) { consumer_private* priv = consumer->local; pthread_mutex_lock( &priv->position_mutex ); @@ -497,11 +459,11 @@ static void set_image_format( mlt_consumer self ) priv->image_format = mlt_image_format_id( format ); if ( mlt_image_invalid == priv->image_format ) priv->image_format = mlt_image_yuv422; - // mlt_image_glsl is for internal use only. + // mlt_image_movit is for internal use only. // Remapping it glsl_texture prevents breaking existing apps // using the legacy "glsl" name. - else if ( mlt_image_glsl == priv->image_format ) - priv->image_format = mlt_image_glsl_texture; + else if ( mlt_image_movit == priv->image_format ) + priv->image_format = mlt_image_opengl_texture; } } @@ -810,7 +772,7 @@ static void *consumer_read_ahead_thread( void *arg ) set_audio_format( self ); set_image_format( self ); - mlt_events_fire( properties, "consumer-thread-started", NULL ); + mlt_events_fire( properties, "consumer-thread-started", mlt_event_data_none() ); // Get the first frame frame = mlt_consumer_get_frame( self ); @@ -828,7 +790,7 @@ static void *consumer_read_ahead_thread( void *arg ) // Get the image of the first frame if ( !video_off ) { - mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", frame, NULL ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", mlt_event_data_from_frame(frame) ); mlt_frame_get_image( frame, &image, &priv->image_format, &width, &height, 0 ); } @@ -906,7 +868,7 @@ static void *consumer_read_ahead_thread( void *arg ) height = mlt_properties_get_int( properties, "height" ); // Get the image - mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", frame, NULL ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", mlt_event_data_from_frame(frame) ); mlt_log_timings_begin(); mlt_frame_get_image( frame, &image, &priv->image_format, &width, &height, 0 ); mlt_log_timings_end( NULL, "mlt_frame_get_image" ); @@ -991,7 +953,7 @@ static void *consumer_read_ahead_thread( void *arg ) priv->queue = NULL; pthread_mutex_unlock( &priv->queue_mutex ); - mlt_events_fire( MLT_CONSUMER_PROPERTIES(self), "consumer-thread-stopped", NULL ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES(self), "consumer-thread-stopped", mlt_event_data_none() ); return NULL; } @@ -1053,7 +1015,7 @@ static void *consumer_worker_thread( void *arg ) if ( preview_off && preview_format != 0 ) format = preview_format; - mlt_events_fire( properties, "consumer-thread-started", NULL ); + mlt_events_fire( properties, "consumer-thread-started", mlt_event_data_none() ); // Continue to read ahead while ( priv->ahead ) @@ -1099,7 +1061,7 @@ static void *consumer_worker_thread( void *arg ) // Fetch width/height again width = mlt_properties_get_int( properties, "width" ); height = mlt_properties_get_int( properties, "height" ); - mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", frame, NULL ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", mlt_event_data_from_frame(frame) ); mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ); } mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); @@ -1140,7 +1102,7 @@ static void consumer_read_ahead_start( mlt_consumer self ) pthread_cond_init( &priv->queue_cond, NULL ); // Create the read ahead - mlt_thread_create( self, (thread_function_t) consumer_read_ahead_thread ); + mlt_thread_create( self, (mlt_thread_function_t) consumer_read_ahead_thread ); priv->started = 1; } @@ -1241,7 +1203,7 @@ static void consumer_read_ahead_stop( mlt_consumer self ) { // Inform thread to stop priv->ahead = 0; - mlt_events_fire( MLT_CONSUMER_PROPERTIES(self), "consumer-stopping", NULL ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES(self), "consumer-stopping", mlt_event_data_none() ); // Broadcast to the condition in case it's waiting pthread_mutex_lock( &priv->queue_mutex ); @@ -1280,7 +1242,7 @@ static void consumer_work_stop( mlt_consumer self ) { // Inform thread to stop priv->ahead = 0; - mlt_events_fire( MLT_CONSUMER_PROPERTIES(self), "consumer-stopping", NULL ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES(self), "consumer-stopping", mlt_event_data_none() ); // Broadcast to the queue condition in case it's waiting pthread_mutex_lock( &priv->queue_mutex ); @@ -1321,7 +1283,7 @@ static void consumer_work_stop( mlt_consumer self ) mlt_deque_close( priv->queue ); mlt_deque_close( priv->worker_threads ); - mlt_events_fire( MLT_CONSUMER_PROPERTIES(self), "consumer-thread-stopped", NULL ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES(self), "consumer-thread-stopped", mlt_event_data_none() ); } } @@ -1603,7 +1565,7 @@ mlt_frame mlt_consumer_rt_frame( mlt_consumer self ) if ( !priv->ahead ) { priv->ahead = 1; - mlt_events_fire( properties, "consumer-thread-started", NULL ); + mlt_events_fire( properties, "consumer-thread-started", mlt_event_data_none() ); } // Get the frame in non real time frame = mlt_consumer_get_frame( self ); @@ -1630,7 +1592,7 @@ mlt_frame mlt_consumer_rt_frame( mlt_consumer self ) void mlt_consumer_stopped( mlt_consumer self ) { mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( self ), "running", 0 ); - mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-stopped", NULL ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-stopped", mlt_event_data_none() ); mlt_event_unblock( ( ( consumer_private* ) self->local )->event_listener ); } @@ -1766,14 +1728,7 @@ mlt_position mlt_consumer_position( mlt_consumer consumer ) return result; } -static void transmit_thread_create( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) -{ - if ( listener ) - listener( owner, self, - (void**) args[0] /* handle */, (int*) args[1] /* priority */, (thread_function_t) args[2], (void*) args[3] /* data */ ); -} - -static void mlt_thread_create( mlt_consumer self, thread_function_t function ) +static void mlt_thread_create(mlt_consumer self, mlt_thread_function_t function ) { consumer_private *priv = self->local; mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); @@ -1782,8 +1737,13 @@ static void mlt_thread_create( mlt_consumer self, thread_function_t function ) { struct sched_param priority; priority.sched_priority = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( self ), "priority" ); - if ( mlt_events_fire( properties, "consumer-thread-create", - &priv->ahead_thread, &priority.sched_priority, function, self, NULL ) < 1 ) + mlt_event_data_thread data = { + .thread = &priv->ahead_thread, + .priority = &priority.sched_priority, + .function = function, + .data = self + }; + if ( mlt_events_fire( properties, "consumer-thread-create", mlt_event_data_from_object(&data) ) < 1 ) { pthread_attr_t thread_attributes; pthread_attr_init( &thread_attributes ); @@ -1801,8 +1761,13 @@ static void mlt_thread_create( mlt_consumer self, thread_function_t function ) else { int priority = -1; - if ( mlt_events_fire( properties, "consumer-thread-create", - &priv->ahead_thread, &priority, function, self, NULL ) < 1 ) + mlt_event_data_thread data = { + .thread = &priv->ahead_thread, + .priority = &priority, + .function = function, + .data = self + }; + if ( mlt_events_fire( properties, "consumer-thread-create", mlt_event_data_from_object(&data) ) < 1 ) { priv->ahead_thread = malloc( sizeof( pthread_t ) ); pthread_t *handle = priv->ahead_thread; @@ -1811,16 +1776,11 @@ static void mlt_thread_create( mlt_consumer self, thread_function_t function ) } } -static void transmit_thread_join( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) -{ - if ( listener ) - listener( owner, self, (void*) args[0] /* handle */ ); -} - static void mlt_thread_join( mlt_consumer self ) { consumer_private *priv = self->local; - if ( mlt_events_fire( MLT_CONSUMER_PROPERTIES(self), "consumer-thread-join", priv->ahead_thread, NULL ) < 1 ) + if ( mlt_events_fire( MLT_CONSUMER_PROPERTIES(self), "consumer-thread-join", + mlt_event_data_from_object(priv->ahead_thread) ) < 1 ) { pthread_t *handle = priv->ahead_thread; pthread_join( *handle, NULL ); diff --git a/src/framework/mlt_consumer.h b/src/framework/mlt_consumer.h index 9000e1da6..3b776c08b 100644 --- a/src/framework/mlt_consumer.h +++ b/src/framework/mlt_consumer.h @@ -3,7 +3,7 @@ * \brief abstraction for all consumer services * \see mlt_consumer_s * - * Copyright (C) 2003-2015 Meltytech, LLC + * Copyright (C) 2003-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 @@ -51,12 +51,15 @@ * environment variable MLT_TEST_CARD. If undefined, the hard-coded default test card is * white silence. A test card is what appears when nothing is produced. * \event \em consumer-frame-show Subclass implementations fire this immediately after showing a frame - * or when a frame should be shown (if audio-only consumer). - * \event \em consumer-frame-render The base class fires this immediately before rendering a frame. + * or when a frame should be shown (if audio-only consumer). The event data is a frame. + * \event \em consumer-frame-render The base class fires this immediately before rendering a frame; + * the event data is a frame. * \event \em consumer-thread-create Override the implementation of creating and * starting a thread by listening and responding to this (real_time 1 or -1 only). + * The event data is a pointer to mlt_event_data_thread. * \event \em consumer-thread-join Override the implementation of waiting and * joining a terminated thread by listening and responding to this (real_time 1 or -1 only). + * The event data is a pointer to mlt_event_data_thread. * \event \em consumer-thread-started The base class fires when beginning execution of a rendering thread. * \event \em consumer-thread-stopped The base class fires when a rendering thread has ended. * \event \em consumer-stopping This is fired when stop was requested, but before render threads are joined. diff --git a/src/framework/mlt_events.c b/src/framework/mlt_events.c index 6051befcd..dcb5b8b2c 100644 --- a/src/framework/mlt_events.c +++ b/src/framework/mlt_events.c @@ -3,7 +3,7 @@ * \brief event handling * \see mlt_events_struct * - * Copyright (C) 2004-2019 Meltytech, LLC + * Copyright (C) 2004-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 @@ -21,9 +21,9 @@ */ #include -#include #include #include +#include #include "mlt_properties.h" #include "mlt_events.h" @@ -48,7 +48,7 @@ static int events_destroyed = 0; struct mlt_events_struct { mlt_properties owner; - mlt_properties list; + mlt_properties listeners; }; typedef struct mlt_events_struct *mlt_events; @@ -59,11 +59,11 @@ typedef struct mlt_events_struct *mlt_events; struct mlt_event_struct { - mlt_events owner; + mlt_events parent; int ref_count; int block_count; mlt_listener listener; - void *service; + void *listener_data; }; /** Increment the reference count on self event. @@ -86,7 +86,7 @@ void mlt_event_inc_ref( mlt_event self ) void mlt_event_block( mlt_event self ) { - if ( self != NULL && self->owner != NULL ) + if ( self != NULL && self->parent != NULL ) self->block_count ++; } @@ -98,7 +98,7 @@ void mlt_event_block( mlt_event self ) void mlt_event_unblock( mlt_event self ) { - if ( self != NULL && self->owner != NULL ) + if ( self != NULL && self->parent != NULL ) self->block_count --; } @@ -113,7 +113,7 @@ void mlt_event_close( mlt_event self ) if ( self != NULL ) { if ( -- self->ref_count == 1 ) - self->owner = NULL; + self->parent = NULL; if ( self->ref_count <= 0 ) { #ifdef _MLT_EVENT_CHECKS_ @@ -142,31 +142,29 @@ void mlt_events_init( mlt_properties self ) if (!events && self) { events = calloc( 1, sizeof( struct mlt_events_struct ) ); if (events) { - events->list = mlt_properties_new( ); + events->listeners = mlt_properties_new( ); events->owner = self; mlt_properties_set_data( self, "_events", events, 0, ( mlt_destructor )mlt_events_close, NULL ); } } } -/** Register an event and transmitter. +/** Register an event. * * \public \memberof mlt_events_struct * \param self a properties list * \param id the name of an event - * \param transmitter the callback function to send an event message * \return true if there was an error */ -int mlt_events_register( mlt_properties self, const char *id, mlt_transmitter transmitter ) +int mlt_events_register(mlt_properties self, const char *id) { int error = 1; mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { - mlt_properties list = events->list; + mlt_properties list = events->listeners; char temp[ 128 ]; - error = mlt_properties_set_data( list, id, transmitter, 0, NULL, NULL ); sprintf( temp, "list:%s", id ); if ( mlt_properties_get_data( list, temp, NULL ) == NULL ) mlt_properties_set_data( list, temp, mlt_properties_new( ), 0, ( mlt_destructor )mlt_properties_close, NULL ); @@ -176,47 +174,33 @@ int mlt_events_register( mlt_properties self, const char *id, mlt_transmitter tr /** Fire an event. * - * This takes a variable number of arguments to supply to the listener. - * \public \memberof mlt_events_struct * \param self a properties list * \param id the name of an event + * \param event_data an event data object * \return the number of listeners */ -int mlt_events_fire( mlt_properties self, const char *id, ... ) +int mlt_events_fire(mlt_properties self, const char *id, mlt_event_data event_data) { int result = 0; mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { - int i = 0; - va_list alist; - void *args[ 10 ]; - mlt_properties list = events->list; + mlt_properties list = events->listeners; mlt_properties listeners = NULL; char temp[ 128 ]; - mlt_transmitter transmitter = mlt_properties_get_data( list, id, NULL ); sprintf( temp, "list:%s", id ); listeners = mlt_properties_get_data( list, temp, NULL ); - va_start( alist, id ); - do - args[ i ] = va_arg( alist, void * ); - while( args[ i ++ ] != NULL ); - va_end( alist ); - if ( listeners != NULL ) { - for ( i = 0; i < mlt_properties_count( listeners ); i ++ ) + for ( int i = 0; i < mlt_properties_count( listeners ); i ++ ) { mlt_event event = mlt_properties_get_data_at( listeners, i, NULL ); - if ( event != NULL && event->owner != NULL && event->block_count == 0 ) + if ( event != NULL && event->parent != NULL && event->block_count == 0 ) { - if ( transmitter != NULL ) - transmitter( event->listener, event->owner->owner, event->service, args ); - else - event->listener( event->owner->owner, event->service ); + event->listener( event->parent->owner, event->listener_data, event_data ); ++result; } } @@ -229,19 +213,19 @@ int mlt_events_fire( mlt_properties self, const char *id, ... ) * * \public \memberof mlt_events_struct * \param self a properties list - * \param service an opaque pointer + * \param listener_data an opaque pointer * \param id the name of the event to listen for * \param listener the callback to receive an event message - * \return + * \return an event */ -mlt_event mlt_events_listen( mlt_properties self, void *service, const char *id, mlt_listener listener ) +mlt_event mlt_events_listen( mlt_properties self, void *listener_data, const char *id, mlt_listener listener ) { mlt_event event = NULL; mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { - mlt_properties list = events->list; + mlt_properties list = events->listeners; mlt_properties listeners = NULL; char temp[ 128 ]; sprintf( temp, "list:%s", id ); @@ -253,12 +237,12 @@ mlt_event mlt_events_listen( mlt_properties self, void *service, const char *id, for ( i = 0; event == NULL && i < mlt_properties_count( listeners ); i ++ ) { mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL ); - if ( entry != NULL && entry->owner != NULL ) + if ( entry != NULL && entry->parent != NULL ) { - if ( entry->service == service && entry->listener == listener ) + if ( entry->listener_data == listener_data && entry->listener == listener ) event = entry; } - else if ( ( entry == NULL || entry->owner == NULL ) && first_null == -1 ) + else if ( ( entry == NULL || entry->parent == NULL ) && first_null == -1 ) { first_null = i; } @@ -273,11 +257,11 @@ mlt_event mlt_events_listen( mlt_properties self, void *service, const char *id, events_created ++; #endif sprintf( temp, "%d", first_null == -1 ? mlt_properties_count( listeners ) : first_null ); - event->owner = events; + event->parent = events; event->ref_count = 0; event->block_count = 0; event->listener = listener; - event->service = service; + event->listener_data = listener_data; mlt_properties_set_data( listeners, temp, event, 0, ( mlt_destructor )mlt_event_close, NULL ); mlt_event_inc_ref( event ); } @@ -288,20 +272,20 @@ mlt_event mlt_events_listen( mlt_properties self, void *service, const char *id, return event; } -/** Block all events for a given service. +/** Block all events for a given listener_data. * * \public \memberof mlt_events_struct * \param self a properties list - * \param service an opaque pointer + * \param listener_data the listener's opaque data pointer */ -void mlt_events_block( mlt_properties self, void *service ) +void mlt_events_block( mlt_properties self, void *listener_data ) { mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { int i = 0, j = 0; - mlt_properties list = events->list; + mlt_properties list = events->listeners; for ( j = 0; j < mlt_properties_count( list ); j ++ ) { char *temp = mlt_properties_get_name( list, j ); @@ -311,7 +295,7 @@ void mlt_events_block( mlt_properties self, void *service ) for ( i = 0; i < mlt_properties_count( listeners ); i ++ ) { mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL ); - if ( entry != NULL && entry->service == service ) + if ( entry != NULL && entry->listener_data == listener_data ) mlt_event_block( entry ); } } @@ -319,20 +303,20 @@ void mlt_events_block( mlt_properties self, void *service ) } } -/** Unblock all events for a given service. +/** Unblock all events for a given listener_data. * * \public \memberof mlt_events_struct * \param self a properties list - * \param service an opaque pointer + * \param listener_data the listener's opaque data pointer */ -void mlt_events_unblock( mlt_properties self, void *service ) +void mlt_events_unblock( mlt_properties self, void *listener_data ) { mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { int i = 0, j = 0; - mlt_properties list = events->list; + mlt_properties list = events->listeners; for ( j = 0; j < mlt_properties_count( list ); j ++ ) { char *temp = mlt_properties_get_name( list, j ); @@ -342,7 +326,7 @@ void mlt_events_unblock( mlt_properties self, void *service ) for ( i = 0; i < mlt_properties_count( listeners ); i ++ ) { mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL ); - if ( entry != NULL && entry->service == service ) + if ( entry != NULL && entry->listener_data == listener_data ) mlt_event_unblock( entry ); } } @@ -350,20 +334,20 @@ void mlt_events_unblock( mlt_properties self, void *service ) } } -/** Disconnect all events for a given service. +/** Disconnect all events for a given listener_data. * * \public \memberof mlt_events_struct * \param self a properties list - * \param service an opaque pointer + * \param listener_data the listener's opaque data pointer */ -void mlt_events_disconnect( mlt_properties self, void *service ) +void mlt_events_disconnect( mlt_properties self, void *listener_data ) { mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { int i = 0, j = 0; - mlt_properties list = events->list; + mlt_properties list = events->listeners; for ( j = 0; j < mlt_properties_count( list ); j ++ ) { char *temp = mlt_properties_get_name( list, j ); @@ -374,7 +358,7 @@ void mlt_events_disconnect( mlt_properties self, void *service ) { mlt_event entry = mlt_properties_get_data_at( listeners, i, NULL ); char *name = mlt_properties_get_name( listeners, i ); - if ( entry != NULL && entry->service == service ) + if ( entry != NULL && entry->listener_data == listener_data ) mlt_properties_set_data( listeners, name, NULL, 0, NULL, NULL ); } } @@ -433,7 +417,7 @@ void mlt_events_wait_for( mlt_properties self, mlt_event event ) { if ( event != NULL ) { - condition_pair *pair = event->service; + condition_pair *pair = event->listener_data; pthread_cond_wait( &pair->cond, &pair->mutex ); } } @@ -449,8 +433,8 @@ void mlt_events_close_wait_for( mlt_properties self, mlt_event event ) { if ( event != NULL ) { - condition_pair *pair = event->service; - event->owner = NULL; + condition_pair *pair = event->listener_data; + event->parent = NULL; pthread_mutex_unlock( &pair->mutex ); pthread_mutex_destroy( &pair->mutex ); pthread_cond_destroy( &pair->cond ); @@ -483,7 +467,124 @@ static void mlt_events_close( mlt_events events ) { if ( events != NULL ) { - mlt_properties_close( events->list ); + mlt_properties_close( events->listeners ); free( events ); } } + +/** Initialize an empty event data. + * + * \public \memberof mlt_event_data + * \return an event data object + */ + +mlt_event_data mlt_event_data_none() +{ + mlt_event_data event_data; + event_data.u.p = NULL; + return event_data; +} + +/** Initialize event data with an integer. + * + * \public \memberof mlt_event_data + * \param value the integer with which to initialize the event data + * \return an event data object + */ + +mlt_event_data mlt_event_data_from_int(int value) +{ + mlt_event_data event_data; + event_data.u.i = value; + return event_data; +} + +/** Get an integer from the event data. + * + * \public \memberof mlt_event_data + * \param event_data an event data object + * \return an integer + */ + +int mlt_event_data_to_int(mlt_event_data event_data) +{ + return event_data.u.i; +} + +/** Initialize event data with a string. + * + * \public \memberof mlt_event_data + * \param value the string with which to initialize the event data + * \return an event data object + */ + +mlt_event_data mlt_event_data_from_string(const char *value) +{ + mlt_event_data event_data; + event_data.u.p = (void*) value; + return event_data; +} + +/** Get a string from the event data. + * + * \public \memberof mlt_event_data + * \param event_data an event data object + * \return a string + */ + +const char *mlt_event_data_to_string(mlt_event_data event_data) +{ + return event_data.u.p; +} + +/** Initialize event data with a frame. + * + * \public \memberof mlt_event_data + * \param frame the frame with which to initialize the event data + * \return an event data object + */ + +mlt_event_data mlt_event_data_from_frame(mlt_frame frame) +{ + mlt_event_data event_data; + event_data.u.p = frame; + return event_data; +} + +/** Get a frame from the event data. + * + * \public \memberof mlt_event_data + * \param event_data an event data object + * \return a frame + */ + +mlt_frame mlt_event_data_to_frame(mlt_event_data event_data) +{ + return (mlt_frame) event_data.u.p; +} + +/** Initialize event data with opaque data. + * + * \public \memberof mlt_event_data + * \param value the pointer with which to initialize the event data + * \return an event data object + */ + +mlt_event_data mlt_event_data_from_object(void *value) +{ + mlt_event_data event_data; + event_data.u.p = value; + return event_data; +} + +/** Get a pointer from the event data. + * + * \public \memberof mlt_event_data + * \param event_data an event data object + * \return a pointer + */ + +void *mlt_event_data_to_object(mlt_event_data event_data) +{ + return event_data.u.p; +} diff --git a/src/framework/mlt_events.h b/src/framework/mlt_events.h index f2637595f..9c643f928 100644 --- a/src/framework/mlt_events.h +++ b/src/framework/mlt_events.h @@ -3,7 +3,7 @@ * \brief event handling * \see mlt_events_struct * - * Copyright (C) 2004-2014 Meltytech, LLC + * Copyright (C) 2004-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 @@ -25,29 +25,36 @@ #include "mlt_types.h" -#if GCC_VERSION >= 40000 -typedef void ( *mlt_transmitter )( void *, ... ); -typedef void ( *mlt_listener )( void *, ... ); -#else -/** callback function to send an event message - * - */ -typedef void ( *mlt_transmitter )( ); +/** A container for data that may be supplied with an event */ +typedef struct { + union { + int i; + void *p; + } u; +} mlt_event_data; + +/** An event data structure to convey thread parameters */ +typedef struct { + void **thread; /**< a pointer to a thread object or handle as determined by you */ + int *priority; /**< a priority level for the thread */ + mlt_thread_function_t function; /**< a pointer to the function that thread will run */ + void *data; /**< an opaque data pointer to pass along */ +} mlt_event_data_thread; + /** event handler when receiving an event message * \param the properties object on which the event was registered - * \param an opaque pointer to a service or really an object - * \param variable args supplied by the transmitter + * \param an opaque pointer to the listener's data + * \param an event data object */ -typedef void ( *mlt_listener )( ); -#endif +typedef void ( *mlt_listener )( mlt_properties, void*, mlt_event_data ); extern void mlt_events_init( mlt_properties self ); -extern int mlt_events_register( mlt_properties self, const char *id, mlt_transmitter transmitter ); -extern int mlt_events_fire( mlt_properties self, const char *id, ... ); -extern mlt_event mlt_events_listen( mlt_properties self, void *service, const char *id, mlt_listener listener ); -extern void mlt_events_block( mlt_properties self, void *service ); -extern void mlt_events_unblock( mlt_properties self, void *service ); -extern void mlt_events_disconnect( mlt_properties self, void *service ); +extern int mlt_events_register( mlt_properties self, const char *id ); +extern int mlt_events_fire( mlt_properties self, const char *id, mlt_event_data ); +extern mlt_event mlt_events_listen( mlt_properties self, void *listener_data, const char *id, mlt_listener listener ); +extern void mlt_events_block( mlt_properties self, void *listener_data ); +extern void mlt_events_unblock( mlt_properties self, void *listener_data ); +extern void mlt_events_disconnect( mlt_properties self, void *listener_data ); extern mlt_event mlt_events_setup_wait_for( mlt_properties self, const char *id ); extern void mlt_events_wait_for( mlt_properties self, mlt_event event ); @@ -58,5 +65,14 @@ extern void mlt_event_block( mlt_event self ); extern void mlt_event_unblock( mlt_event self ); extern void mlt_event_close( mlt_event self ); -#endif +extern mlt_event_data mlt_event_data_none(); +extern mlt_event_data mlt_event_data_from_int(int value); +extern int mlt_event_data_to_int(mlt_event_data); +extern mlt_event_data mlt_event_data_from_string(const char *value); +extern const char* mlt_event_data_to_string(mlt_event_data); +extern mlt_event_data mlt_event_data_from_frame(mlt_frame); +extern mlt_frame mlt_event_data_to_frame(mlt_event_data); +extern mlt_event_data mlt_event_data_from_object(void*); +extern void* mlt_event_data_to_object(mlt_event_data); +#endif diff --git a/src/framework/mlt_factory.c b/src/framework/mlt_factory.c index 775aaf733..6a0e211e3 100644 --- a/src/framework/mlt_factory.c +++ b/src/framework/mlt_factory.c @@ -2,7 +2,7 @@ * \file mlt_factory.c * \brief the factory method interfaces * - * Copyright (C) 2003-2019 Meltytech, LLC + * Copyright (C) 2003-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 @@ -69,36 +69,6 @@ static mlt_properties event_object = NULL; /** for tracking the unique_id set on each constructed service */ static int unique_id = 0; -/* Event transmitters. */ - -/** the -create-request event transmitter - * - * \param listener - * \param owner - * \param self - * \param args - */ - -static void mlt_factory_create_request( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) -{ - if ( listener != NULL ) - listener( owner, self, ( char * )args[ 0 ], ( char * )args[ 1 ], ( mlt_service * )args[ 2 ] ); -} - -/** the -create-done event transmitter - * - * \param listener - * \param owner - * \param self - * \param args - */ - -static void mlt_factory_create_done( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) -{ - if ( listener != NULL ) - listener( owner, self, ( char * )args[ 0 ], ( char * )args[ 1 ], ( mlt_service )args[ 2 ] ); -} - #if defined(_WIN32) || (defined(__APPLE__) && defined(RELOCATABLE)) // Replacement for buggy dirname() on some systems. // https://github.com/mltframework/mlt/issues/285 @@ -218,14 +188,14 @@ mlt_repository mlt_factory_init( const char *directory ) // Create and set up the events object event_object = mlt_properties_new( ); mlt_events_init( event_object ); - mlt_events_register( event_object, "producer-create-request", ( mlt_transmitter )mlt_factory_create_request ); - mlt_events_register( event_object, "producer-create-done", ( mlt_transmitter )mlt_factory_create_done ); - mlt_events_register( event_object, "filter-create-request", ( mlt_transmitter )mlt_factory_create_request ); - mlt_events_register( event_object, "filter-create-done", ( mlt_transmitter )mlt_factory_create_done ); - mlt_events_register( event_object, "transition-create-request", ( mlt_transmitter )mlt_factory_create_request ); - mlt_events_register( event_object, "transition-create-done", ( mlt_transmitter )mlt_factory_create_done ); - mlt_events_register( event_object, "consumer-create-request", ( mlt_transmitter )mlt_factory_create_request ); - mlt_events_register( event_object, "consumer-create-done", ( mlt_transmitter )mlt_factory_create_done ); + mlt_events_register( event_object, "producer-create-request" ); + mlt_events_register( event_object, "producer-create-done" ); + mlt_events_register( event_object, "filter-create-request" ); + mlt_events_register( event_object, "filter-create-done" ); + mlt_events_register( event_object, "transition-create-request" ); + mlt_events_register( event_object, "transition-create-done" ); + mlt_events_register( event_object, "consumer-create-request" ); + mlt_events_register( event_object, "consumer-create-done" ); // Create the repository of services repository = mlt_repository_init( mlt_directory ); @@ -354,17 +324,30 @@ mlt_producer mlt_factory_producer( mlt_profile profile, const char *service, con service = mlt_environment( "MLT_PRODUCER" ); // Offer the application the chance to 'create' - mlt_events_fire( event_object, "producer-create-request", service, resource, &obj, NULL ); + mlt_factory_event_data data = { + .name = service, + .input = resource, + .service = &obj + }; + mlt_events_fire( event_object, "producer-create-request", mlt_event_data_from_object(&data) ); // Try to instantiate via the specified service if ( obj == NULL ) { - obj = mlt_repository_create( repository, profile, producer_type, service, resource ); - mlt_events_fire( event_object, "producer-create-done", service, resource, obj, NULL ); + obj = mlt_repository_create( repository, profile, mlt_service_producer_type, service, resource ); + mlt_events_fire( event_object, "producer-create-done", mlt_event_data_from_object(&data) ); if ( obj != NULL ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( obj ); - set_common_properties( properties, profile, "producer", service ); + if ( mlt_service_identify( MLT_PRODUCER_SERVICE( obj ) ) == mlt_service_chain_type ) + { + // XML producer may return a chain + set_common_properties( properties, profile, "chain", service ); + } + else + { + set_common_properties( properties, profile, "producer", service ); + } } } return obj; @@ -383,12 +366,17 @@ mlt_filter mlt_factory_filter( mlt_profile profile, const char *service, const v mlt_filter obj = NULL; // Offer the application the chance to 'create' - mlt_events_fire( event_object, "filter-create-request", service, input, &obj, NULL ); + mlt_factory_event_data data = { + .name = service, + .input = input, + .service = &obj + }; + mlt_events_fire( event_object, "filter-create-request", mlt_event_data_from_object(&data) ); if ( obj == NULL ) { - obj = mlt_repository_create( repository, profile, filter_type, service, input ); - mlt_events_fire( event_object, "filter-create-done", service, input, obj, NULL ); + obj = mlt_repository_create( repository, profile, mlt_service_filter_type, service, input ); + mlt_events_fire( event_object, "filter-create-done", mlt_event_data_from_object(&data) ); } if ( obj != NULL ) @@ -399,6 +387,39 @@ mlt_filter mlt_factory_filter( mlt_profile profile, const char *service, const v return obj; } +/** Fetch a link from the repository. + * + * \param service the name of the link + * \param input an optional argument to the link constructor, typically a string + * \return a new link + */ + +mlt_link mlt_factory_link( const char *service, const void *input ) +{ + mlt_link obj = NULL; + + // Offer the application the chance to 'create' + mlt_factory_event_data data = { + .name = service, + .input = input, + .service = &obj + }; + mlt_events_fire( event_object, "link-create-request", mlt_event_data_from_object(&data) ); + + if ( obj == NULL ) + { + obj = mlt_repository_create( repository, NULL, mlt_service_link_type, service, input ); + mlt_events_fire( event_object, "link-create-done", mlt_event_data_from_object(&data) ); + } + + if ( obj != NULL ) + { + mlt_properties properties = MLT_LINK_PROPERTIES( obj ); + set_common_properties( properties, NULL, "link", service ); + } + return obj; +} + /** Fetch a transition from the repository. * * \param profile the \p mlt_profile to use @@ -412,12 +433,17 @@ mlt_transition mlt_factory_transition( mlt_profile profile, const char *service, mlt_transition obj = NULL; // Offer the application the chance to 'create' - mlt_events_fire( event_object, "transition-create-request", service, input, &obj, NULL ); + mlt_factory_event_data data = { + .name = service, + .input = input, + .service = &obj + }; + mlt_events_fire( event_object, "transition-create-request", mlt_event_data_from_object(&data) ); if ( obj == NULL ) { - obj = mlt_repository_create( repository, profile, transition_type, service, input ); - mlt_events_fire( event_object, "transition-create-done", service, input, obj, NULL ); + obj = mlt_repository_create( repository, profile, mlt_service_transition_type, service, input ); + mlt_events_fire( event_object, "transition-create-done", mlt_event_data_from_object(&data) ); } if ( obj != NULL ) @@ -444,11 +470,16 @@ mlt_consumer mlt_factory_consumer( mlt_profile profile, const char *service, con service = mlt_environment( "MLT_CONSUMER" ); // Offer the application the chance to 'create' - mlt_events_fire( event_object, "consumer-create-request", service, input, &obj, NULL ); + mlt_factory_event_data data = { + .name = service, + .input = input, + .service = &obj + }; + mlt_events_fire( event_object, "consumer-create-request",mlt_event_data_from_object(&data) ); if ( obj == NULL ) { - obj = mlt_repository_create( repository, profile, consumer_type, service, input ); + obj = mlt_repository_create( repository, profile, mlt_service_consumer_type, service, input ); } if ( obj == NULL ) @@ -456,19 +487,19 @@ mlt_consumer mlt_factory_consumer( mlt_profile profile, const char *service, con if ( !strcmp( service, "sdl2" ) ) { service = "sdl"; - obj = mlt_repository_create( repository, profile, consumer_type, service, input ); + obj = mlt_repository_create( repository, profile, mlt_service_consumer_type, service, input ); } else if ( !strcmp( service, "sdl_audio" ) ) { service = "sdl2_audio"; - obj = mlt_repository_create( repository, profile, consumer_type, service, input ); + obj = mlt_repository_create( repository, profile, mlt_service_consumer_type, service, input ); } } if ( obj != NULL ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( obj ); - mlt_events_fire( event_object, "consumer-create-done", service, input, obj, NULL ); + mlt_events_fire( event_object, "consumer-create-done", mlt_event_data_from_object(&data) ); set_common_properties( properties, profile, "consumer", service ); } return obj; diff --git a/src/framework/mlt_factory.h b/src/framework/mlt_factory.h index 57660ab45..5ae7f53f1 100644 --- a/src/framework/mlt_factory.h +++ b/src/framework/mlt_factory.h @@ -2,7 +2,7 @@ * \file mlt_factory.h * \brief the factory method interfaces * - * Copyright (C) 2003-2018 Meltytech, LLC + * Copyright (C) 2003-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 @@ -35,14 +35,26 @@ * \envvar \em MLT_REPOSITORY overrides the default location of the plugin modules, defaults to \p PREFIX_LIB. * MLT_REPOSITORY is ignored on Windows and OS X relocatable builds. * \envvar \em MLT_PRESETS_PATH overrides the default full path to the properties preset files, defaults to \p MLT_DATA/presets - * \event \em producer-create-request fired when mlt_factory_producer is called - * \event \em producer-create-done fired when a producer registers itself - * \event \em filter-create-request fired when mlt_factory_filter is called - * \event \em filter-create-done fired when a filter registers itself - * \event \em transition-create-request fired when mlt_factory_transition is called - * \event \em transition-create-done fired when a transition registers itself - * \event \em consumer-create-request fired when mlt_factory_consumer is called - * \event \em consumer-create-done fired when a consumer registers itself + * \event \em producer-create-request fired when mlt_factory_producer is called; + * the event data is a pointer to mlt_factory_event_data + * \event \em producer-create-done fired when a producer registers itself; + * the event data is a pointer to mlt_factory_event_data + * \event \em filter-create-request fired when mlt_factory_filter is called; + * the event data is a pointer to mlt_factory_event_data + * \event \em filter-create-done fired when a filter registers itself; + * the event data is a pointer to mlt_factory_event_data + * \event \em transition-create-request fired when mlt_factory_transition is called; + * the event data is a pointer to mlt_factory_event_data + * \event \em transition-create-done fired when a transition registers itself; + * the event data is a pointer to mlt_factory_event_data + * \event \em consumer-create-request fired when mlt_factory_consumer is called; + * the event data is a pointer to mlt_factory_event_data + * \event \em consumer-create-done fired when a consumer registers itself; + * the event data is a pointer to mlt_factory_event_data + * \event \em link-create-request fired when mlt_factory_link is called; + * the event data is a pointer to mlt_factory_event_data + * \event \em link-create-done fired when a link registers itself; + * the event data is a pointer to mlt_factory_event_data */ extern mlt_repository mlt_factory_init( const char *directory ); @@ -53,10 +65,19 @@ extern int mlt_environment_set( const char *name, const char *value ); extern mlt_properties mlt_factory_event_object( ); extern mlt_producer mlt_factory_producer( mlt_profile profile, const char *service, const void *resource ); extern mlt_filter mlt_factory_filter( mlt_profile profile, const char *name, const void *input ); +extern mlt_link mlt_factory_link( const char *name, const void *input ); extern mlt_transition mlt_factory_transition( mlt_profile profile, const char *name, const void *input ); extern mlt_consumer mlt_factory_consumer( mlt_profile profile, const char *name, const void *input ); extern void mlt_factory_register_for_clean_up( void *ptr, mlt_destructor destructor ); extern void mlt_factory_close( ); extern mlt_properties mlt_global_properties( ); +/** The event data for all factory-related events */ + +typedef struct { + const char *name; /**< the name of the service requested */ + const void *input; /**< an argument supplied to initialize the service, typically a string */ + void *service; /**< the service being created */ +} mlt_factory_event_data; + #endif diff --git a/src/framework/mlt_field.c b/src/framework/mlt_field.c index 72a68de54..4e3425e71 100644 --- a/src/framework/mlt_field.c +++ b/src/framework/mlt_field.c @@ -183,7 +183,7 @@ int mlt_field_plant_filter( mlt_field self, mlt_filter that, int track ) mlt_tractor_connect( self->tractor, self->producer ); // Fire an event - mlt_events_fire( mlt_field_properties( self ), "service-changed", NULL ); + mlt_events_fire( mlt_field_properties( self ), "service-changed", mlt_event_data_none() ); } return result; @@ -214,7 +214,7 @@ int mlt_field_plant_transition( mlt_field self, mlt_transition that, int a_track mlt_tractor_connect( self->tractor, self->producer ); // Fire an event - mlt_events_fire( mlt_field_properties( self ), "service-changed", NULL ); + mlt_events_fire( mlt_field_properties( self ), "service-changed", mlt_event_data_none() ); } return result; @@ -250,20 +250,20 @@ void mlt_field_disconnect_service( mlt_field self, mlt_service service ) int i; switch ( mlt_service_identify(c) ) { - case filter_type: + case mlt_service_filter_type: i = mlt_filter_get_track( MLT_FILTER(c) ); mlt_service_connect_producer( c, p, i ); break; - case transition_type: + case mlt_service_transition_type: i = mlt_transition_get_a_track ( MLT_TRANSITION(c) ); mlt_service_connect_producer( c, p, i ); MLT_TRANSITION(c)->producer = p; break; - case tractor_type: + case mlt_service_tractor_type: self->producer = p; mlt_tractor_connect( MLT_TRACTOR(c), p ); default: break; } - mlt_events_fire( mlt_field_properties( self ), "service-changed", NULL ); + mlt_events_fire( mlt_field_properties( self ), "service-changed", mlt_event_data_none() ); } diff --git a/src/framework/mlt_frame.c b/src/framework/mlt_frame.c index 8f395479a..9bc3a43c9 100644 --- a/src/framework/mlt_frame.c +++ b/src/framework/mlt_frame.c @@ -21,6 +21,7 @@ */ #include "mlt_frame.h" +#include "mlt_image.h" #include "mlt_producer.h" #include "mlt_factory.h" #include "mlt_profile.h" @@ -348,7 +349,6 @@ int mlt_frame_set_image( mlt_frame self, uint8_t *image, int size, mlt_destructo int mlt_frame_set_alpha( mlt_frame self, uint8_t *alpha, int size, mlt_destructor destroy ) { - self->get_alpha_mask = NULL; return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "alpha", alpha, size, destroy, NULL ); } @@ -388,94 +388,6 @@ void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format f mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "width", width ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "height", height ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "format", format ); - self->get_alpha_mask = NULL; -} - -/** Get the short name for an image format. - * - * \public \memberof mlt_frame_s - * \param format the image format - * \return a string - */ - -const char * mlt_image_format_name( mlt_image_format format ) -{ - switch ( format ) - { - case mlt_image_none: return "none"; - case mlt_image_rgb24: return "rgb24"; - case mlt_image_rgb24a: return "rgb24a"; - case mlt_image_yuv422: return "yuv422"; - case mlt_image_yuv420p: return "yuv420p"; - case mlt_image_opengl: return "opengl"; - case mlt_image_glsl: return "glsl"; - case mlt_image_glsl_texture: return "glsl_texture"; - case mlt_image_yuv422p16: return "yuv422p16"; - case mlt_image_invalid: return "invalid"; - } - return "invalid"; -} - -/** Get the id of image format from short name. - * - * \public \memberof mlt_frame_s - * \param name the image format short name - * \return a image format - */ - -mlt_image_format mlt_image_format_id( const char * name ) -{ - mlt_image_format f; - - for( f = mlt_image_none; name && f < mlt_image_invalid; f++ ) - { - const char * v = mlt_image_format_name( f ); - if( !strcmp( v, name ) ) - return f; - } - - return mlt_image_invalid; -} - -/** Get the number of bytes needed for an image. - * - * \public \memberof mlt_frame_s - * \param format the image format - * \param width width of the image in pixels - * \param height height of the image in pixels - * \param[out] bpp the number of bytes per pixel (optional) - * \return the number of bytes - */ -int mlt_image_format_size( mlt_image_format format, int width, int height, int *bpp ) -{ - height += 1; - switch ( format ) - { - case mlt_image_rgb24: - if ( bpp ) *bpp = 3; - return width * height * 3; - case mlt_image_opengl: - case mlt_image_rgb24a: - if ( bpp ) *bpp = 4; - return width * height * 4; - case mlt_image_yuv422: - if ( bpp ) *bpp = 2; - return width * height * 2; - case mlt_image_yuv420p: - if ( bpp ) *bpp = 3 / 2; - return width * height * 3 / 2; - case mlt_image_glsl: - case mlt_image_glsl_texture: - if ( bpp ) *bpp = 0; - return 4; - case mlt_image_yuv422p16: - if ( bpp ) *bpp = 0; - return 4 * height * width ; - default: - if ( bpp ) *bpp = 0; - return 0; - } - return 0; } static int generate_test_image( mlt_properties properties, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) @@ -511,75 +423,34 @@ static int generate_test_image( mlt_properties properties, uint8_t **buffer, ml } if ( error && buffer ) { - int size = 0; - *width = *width == 0 ? 720 : *width; *height = *height == 0 ? 576 : *height; - size = *width * *height; - - mlt_properties_set_int( properties, "format", *format ); - mlt_properties_set_int( properties, "width", *width ); - mlt_properties_set_int( properties, "height", *height ); - mlt_properties_set_double( properties, "aspect_ratio", 1.0 ); - switch( *format ) { - case mlt_image_rgb24: - size *= 3; - size += *width * 3; - *buffer = mlt_pool_alloc( size ); - if ( *buffer ) - memset( *buffer, 255, size ); - break; - case mlt_image_rgb24a: - case mlt_image_opengl: - size *= 4; - size += *width * 4; - *buffer = mlt_pool_alloc( size ); - if ( *buffer ) - memset( *buffer, 255, size ); - break; - case mlt_image_none: - case mlt_image_glsl: - case mlt_image_glsl_texture: - *format = mlt_image_yuv422; + case mlt_image_rgb: + case mlt_image_rgba: case mlt_image_yuv422: - size *= 2; - size += *width * 2; - *buffer = mlt_pool_alloc( size ); - if ( *buffer ) - { - register uint8_t *p = *buffer; - register uint8_t *q = p + size; - while ( p != NULL && p != q ) - { - *p ++ = 235; - *p ++ = 128; - } - } - break; case mlt_image_yuv422p16: case mlt_image_yuv420p: - size = mlt_image_format_size( *format, *width, *height, NULL ); - *buffer = mlt_pool_alloc( size ); - if ( *buffer ) - { - int strides[4]; - uint8_t* planes[4]; - int h = *height; - mlt_image_format_planes( *format, *width, *height, *buffer, planes, strides ); - memset(planes[0], 235, h * strides[0]); - if ( *format == mlt_image_yuv420p ) - h /= 2; - memset(planes[1], 128, h * strides[1]); - memset(planes[2], 128, h * strides[2]); - } break; - default: - size = 0; + case mlt_image_none: + case mlt_image_movit: + case mlt_image_opengl_texture: + *format = mlt_image_yuv422; break; } - mlt_properties_set_data( properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); + + struct mlt_image_s img; + mlt_image_set_values( &img, NULL, *format, *width, *height ); + mlt_image_alloc_data( &img ); + mlt_image_fill_black( &img ); + + *buffer = img.data; + mlt_properties_set_int( properties, "format", *format ); + mlt_properties_set_int( properties, "width", *width ); + mlt_properties_set_int( properties, "height", *height ); + mlt_properties_set_double( properties, "aspect_ratio", 1.0 ); + mlt_properties_set_data( properties, "image", *buffer, 0, img.release_data, NULL ); mlt_properties_set_int( properties, "test_image", 1 ); error = 0; } @@ -651,41 +522,7 @@ int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *for return error; } -/** Get the alpha channel associated to the frame. - * - * Unlike mlt_frame_get_alpha(), this function WILL create an opaque alpha - * channel if one does not already exist. - * - * \public \memberof mlt_frame_s - * \deprecated use mlt_frame_get_alpha() instead - * \param self a frame - * \return the alpha channel - */ - -uint8_t *mlt_frame_get_alpha_mask( mlt_frame self ) -{ - uint8_t *alpha = NULL; - if ( self != NULL ) - { - if ( self->get_alpha_mask != NULL ) - alpha = self->get_alpha_mask( self ); - if ( alpha == NULL ) - alpha = mlt_properties_get_data( &self->parent, "alpha", NULL ); - if ( alpha == NULL ) - { - int size = mlt_properties_get_int( &self->parent, "width" ) * mlt_properties_get_int( &self->parent, "height" ); - alpha = mlt_pool_alloc( size ); - memset( alpha, 255, size ); - mlt_properties_set_data( &self->parent, "alpha", alpha, size, mlt_pool_release, NULL ); - } - } - return alpha; -} - /** Get the alpha channel associated to the frame (without creating if it has not). - * - * Unlike mlt_frame_get_alpha_mask(), this function does NOT create an alpha - * channel if one does not already exist. * * \public \memberof mlt_frame_s * \param self a frame @@ -697,10 +534,7 @@ uint8_t *mlt_frame_get_alpha( mlt_frame self ) uint8_t *alpha = NULL; if ( self != NULL ) { - if ( self->get_alpha_mask != NULL ) - alpha = self->get_alpha_mask( self ); - if ( alpha == NULL ) - alpha = mlt_properties_get_data( &self->parent, "alpha", NULL ); + alpha = mlt_properties_get_data( &self->parent, "alpha", NULL ); } return alpha; } @@ -942,7 +776,7 @@ void mlt_frame_write_ppm( mlt_frame frame ) { int width = 0; int height = 0; - mlt_image_format format = mlt_image_rgb24; + mlt_image_format format = mlt_image_rgb; uint8_t *image; if ( mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ) == 0 ) @@ -1095,63 +929,3 @@ mlt_frame mlt_frame_clone( mlt_frame self, int is_deep ) return new_frame; } - -/** Build a planes pointers of image mapping - * - * For proper and unified planar image processing, planes sizes and planes pointers should - * be provides to processing code. - * - * \public \memberof mlt_frame_s - * \param format the image format - * \param width width of the image in pixels - * \param height height of the image in pixels - * \param[in] data pointer to allocated image - * \param[out] planes pointers to plane's pointers will be set - * \param[out] strides pointers to plane's strides will be set - * \return the number of bytes - */ -int mlt_image_format_planes( mlt_image_format format, int width, int height, void* data, unsigned char *planes[4], int strides[4]) -{ - if ( mlt_image_yuv422p16 == format ) - { - strides[0] = width * 2; - strides[1] = width; - strides[2] = width; - strides[3] = 0; - - planes[0] = (unsigned char*)data; - planes[1] = planes[0] + height * strides[0]; - planes[2] = planes[1] + height * strides[1]; - planes[3] = 0; - } - else if ( mlt_image_yuv420p == format ) - { - strides[0] = width; - strides[1] = width >> 1; - strides[2] = width >> 1; - 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[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[1] = 0; - strides[2] = 0; - strides[3] = 0; - }; - - return 0; -} diff --git a/src/framework/mlt_frame.h b/src/framework/mlt_frame.h index 235e3532a..df83c77f8 100644 --- a/src/framework/mlt_frame.h +++ b/src/framework/mlt_frame.h @@ -24,6 +24,7 @@ #define MLT_FRAME_H #include "mlt_audio.h" +#include "mlt_image.h" #include "mlt_properties.h" #include "mlt_deque.h" #include "mlt_service.h" @@ -74,12 +75,6 @@ struct mlt_frame_s { struct mlt_properties_s parent; /**< \private A frame extends properties. */ - /** Get the alpha channel (callback function). - * \param self a frame - * \return the 8-bit alpha channel - */ - uint8_t * ( *get_alpha_mask )( mlt_frame self ); - /** Convert the image format (callback function). * \param self a frame * \param[in,out] image a buffer of image data @@ -122,7 +117,6 @@ extern int mlt_frame_set_image( mlt_frame self, uint8_t *image, int size, mlt_de extern int mlt_frame_set_alpha( mlt_frame self, uint8_t *alpha, int size, mlt_destructor destroy ); extern void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height ); extern int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ); -extern uint8_t *mlt_frame_get_alpha_mask( mlt_frame self ); extern uint8_t *mlt_frame_get_alpha( mlt_frame self ); extern int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ); extern int mlt_frame_set_audio( mlt_frame self, void *buffer, mlt_audio_format, int size, mlt_destructor ); @@ -145,11 +139,7 @@ extern mlt_properties mlt_frame_get_unique_properties( mlt_frame self, mlt_servi extern mlt_frame mlt_frame_clone( mlt_frame self, int is_deep ); /* convenience functions */ -extern const char * mlt_image_format_name( mlt_image_format format ); -extern int mlt_image_format_size( mlt_image_format format, int width, int height, int *bpp ); extern void mlt_frame_write_ppm( mlt_frame frame ); -extern int mlt_image_format_planes( mlt_image_format format, int width, int height, void* data, unsigned char *planes[4], int strides[4]); -extern mlt_image_format mlt_image_format_id( const char * name ); /** This macro scales RGB into the YUV gamut - y is scaled by 219/255 and uv by 224/255. */ #define RGB2YUV_601_SCALED(r, g, b, y, u, v)\ diff --git a/src/framework/mlt_geometry.c b/src/framework/mlt_geometry.c deleted file mode 100644 index 6cd496e64..000000000 --- a/src/framework/mlt_geometry.c +++ /dev/null @@ -1,714 +0,0 @@ -/** - * \file mlt_geometry.c - * \brief geometry animation API (deprecated) - * \deprecated use mlt_animation_s instead - * - * Copyright (C) 2004-2014 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 "mlt_geometry.h" -#include "mlt_tokeniser.h" -#include "mlt_factory.h" -#include "mlt_profile.h" - -#include -#include -#include - -/** private part of geometry animation item (deprecated) - * \deprecated use mlt_animation_s instead - */ - -typedef struct geometry_item_s -{ - struct mlt_geometry_item_s data; - struct geometry_item_s *next, *prev; -} -*geometry_item; - -/** private part of geometry object (deprecated) - * \deprecated use mlt_animation_s instead - */ - -typedef struct -{ - char *data; - int length; - int nw; - int nh; - geometry_item item; -} -geometry_s, *geometry; - -// Create a new geometry structure -mlt_geometry mlt_geometry_init( ) -{ - mlt_geometry self = calloc( 1, sizeof( struct mlt_geometry_s ) ); - if ( self != NULL ) - { - self->local = calloc( 1, sizeof( geometry_s ) ); - if ( self->local != NULL ) - { - geometry g = self->local; - g->nw = 720; - g->nh = 576; - } - else - { - free( self ); - self = NULL; - } - } - return self; -} - -/** A linear step -*/ - -static inline double linearstep( double start, double end, double position, int length ) -{ - double o = ( end - start ) / length; - return start + position * o; -} - -void mlt_geometry_interpolate( mlt_geometry self ) -{ - geometry g = self->local; - - // Parse of all items to ensure unspecified keys are calculated correctly - if ( g->item != NULL ) - { - int i = 0; - for ( i = 0; i < 5; i ++ ) - { - geometry_item current = g->item; - while( current != NULL ) - { - int fixed = current->data.f[ i ]; - if ( !fixed ) - { - geometry_item prev = current->prev; - geometry_item next = current->next; - - double prev_value = 0; - double next_value = 0; - double value = 0; - - while( prev != NULL && !prev->data.f[ i ] ) prev = prev->prev; - while( next != NULL && !next->data.f[ i ] ) next = next->next; - - switch( i ) - { - case 0: - if ( prev ) prev_value = prev->data.x; - if ( next ) next_value = next->data.x; - break; - case 1: - if ( prev ) prev_value = prev->data.y; - if ( next ) next_value = next->data.y; - break; - case 2: - if ( prev ) prev_value = prev->data.w; - if ( next ) next_value = next->data.w; - break; - case 3: - if ( prev ) prev_value = prev->data.h; - if ( next ) next_value = next->data.h; - break; - case 4: - if ( prev ) prev_value = prev->data.mix; - if ( next ) next_value = next->data.mix; - break; - } - - // This should never happen - if ( prev == NULL ) - current->data.f[ i ] = 1; - else if ( next == NULL ) - value = prev_value; - else - value = linearstep( prev_value, next_value, current->data.frame - prev->data.frame, next->data.frame - prev->data.frame ); - - switch( i ) - { - case 0: current->data.x = value; break; - case 1: current->data.y = value; break; - case 2: current->data.w = value; break; - case 3: current->data.h = value; break; - case 4: current->data.mix = value; break; - } - } - - // Move to the next item - current = current->next; - } - } - } -} - -static int mlt_geometry_drop( mlt_geometry self, geometry_item item ) -{ - geometry g = self->local; - - if ( item == g->item ) - { - g->item = item->next; - if ( g->item != NULL ) - g->item->prev = NULL; - // To ensure correct seeding, ensure all values are fixed - if ( g->item != NULL ) - { - g->item->data.f[0] = 1; - g->item->data.f[1] = 1; - g->item->data.f[2] = 1; - g->item->data.f[3] = 1; - g->item->data.f[4] = 1; - } - } - else if ( item->next != NULL && item->prev != NULL ) - { - item->prev->next = item->next; - item->next->prev = item->prev; - } - else if ( item->next != NULL ) - { - item->next->prev = item->prev; - } - else if ( item->prev != NULL ) - { - item->prev->next = item->next; - } - - free( item ); - - return 0; -} - -static void mlt_geometry_clean( mlt_geometry self ) -{ - geometry g = self->local; - free( g->data ); - g->data = NULL; - while( g->item ) - mlt_geometry_drop( self, g->item ); -} - -// Parse the geometry specification for a given length and normalised width/height (-1 for default) -// data is constructed as: [frame=]X/Y:WxH[:mix][!][;[frame=]X/Y:WxH[:mix][!]]* -// and X, Y, W and H can have trailing % chars to indicate percentage of normalised size -// Append a pair's value with ! to enable distort. -int mlt_geometry_parse( mlt_geometry self, char *data, int length, int nw, int nh ) -{ - int i = 0; - - // Create a tokeniser - mlt_tokeniser tokens = mlt_tokeniser_init( ); - - // Get the local/private structure - geometry g = self->local; - - // Clean the existing geometry - mlt_geometry_clean( self ); - - // Update the info on the data - if ( length != -1 ) - g->length = length; - if ( nw != -1 ) - g->nw = nw; - if ( nh != -1 ) - g->nh = nh; - if ( data != NULL ) - g->data = strdup( data ); - - // Tokenise - if ( data != NULL ) - mlt_tokeniser_parse_new( tokens, data, ";" ); - - // Iterate through each token - for ( i = 0; i < mlt_tokeniser_count( tokens ); i ++ ) - { - struct mlt_geometry_item_s item; - char *value = mlt_tokeniser_get_string( tokens, i ); - - // If no data in keyframe, drop it (trailing semicolon) - if ( value == NULL || !strcmp( value, "" ) ) - continue; - - // Set item to 0 - memset( &item, 0, sizeof( struct mlt_geometry_item_s ) ); - - // Now parse the item - mlt_geometry_parse_item( self, &item, value ); - - // Now insert into place - mlt_geometry_insert( self, &item ); - } - mlt_geometry_interpolate( self ); - - // Remove the tokeniser - mlt_tokeniser_close( tokens ); - - // ??? - return 0; -} - -// Conditionally refresh in case of a change -int mlt_geometry_refresh( mlt_geometry self, char *data, int length, int nw, int nh ) -{ - geometry g = self->local; - int changed = ( length != -1 && length != g->length ); - changed = changed || ( nw != -1 && nw != g->nw ); - changed = changed || ( nh != -1 && nh != g->nh ); - changed = changed || ( data != NULL && ( g->data == NULL || strcmp( data, g->data ) ) ); - if ( changed ) - return mlt_geometry_parse( self, data, length, nw, nh ); - return -1; -} - -int mlt_geometry_get_length( mlt_geometry self ) -{ - // Get the local/private structure - geometry g = self->local; - - // return the length - return g->length; -} - -void mlt_geometry_set_length( mlt_geometry self, int length ) -{ - // Get the local/private structure - geometry g = self->local; - - // set the length - g->length = length; -} - -int mlt_geometry_parse_item( mlt_geometry self, mlt_geometry_item item, char *value ) -{ - int ret = 0; - - // Get the local/private structure - geometry g = self->local; - - if ( value != NULL && strcmp( value, "" ) ) - { - char *p = strchr( value, '=' ); - int count = 0; - double temp; - - // Determine if a position has been specified - if ( p != NULL ) - { - temp = atof( value ); - if ( temp > -1 && temp < 1 ) - item->frame = temp * g->length; - else - item->frame = temp; - value = p + 1; - } - - // Special case - frame < 0 - if ( item->frame < 0 ) - item->frame += g->length; - - // Obtain the current value at this position - self allows new - // frames to be created which don't specify all values - mlt_geometry_fetch( self, item, item->frame ); - - // Special case - when an empty string is specified, all values are fixed - // TODO: Check if this is logical - it's convenient, but it's also odd... - if ( !*value ) - { - item->f[0] = 1; - item->f[1] = 1; - item->f[2] = 1; - item->f[3] = 1; - item->f[4] = 1; - } - - // Iterate through the remainder of value - while( *value ) - { - // Get the value - temp = strtod( value, &p ); - - // Check if a value was specified - if ( p != value ) - { - // Handle the % case - if ( *p == '%' ) - { - if ( count == 0 || count == 2 ) - temp *= g->nw / 100.0; - else if ( count == 1 || count == 3 ) - temp *= g->nh / 100.0; - p ++; - } - - // Special case - distort token - if ( *p == '!' || *p == '*' ) - { - p ++; - item->distort = 1; - } - - // Actually, we don't care about the delimiter at all.. - if ( *p ) p ++; - - // Assign to the item - switch( count ) - { - case 0: item->x = temp; item->f[0] = 1; break; - case 1: item->y = temp; item->f[1] = 1; break; - case 2: item->w = temp; item->f[2] = 1; break; - case 3: item->h = temp; item->f[3] = 1; break; - case 4: item->mix = temp; item->f[4] = 1; break; - } - } - else - { - p ++; - } - - // Update the value pointer - value = p; - count ++; - } - } - else - { - ret = 1; - } - - return ret; -} - -// Fetch a geometry item for an absolute position -int mlt_geometry_fetch( mlt_geometry self, mlt_geometry_item item, float position ) -{ - // Get the local geometry - geometry g = self->local; - - // Need to find the nearest key to the position specified - geometry_item key = g->item; - - // Iterate through the keys until we reach last or have - while( key != NULL && key->next != NULL && position >= key->next->data.frame ) - key = key->next; - - if ( key != NULL ) - { - // Position is situated before the first key - all zeroes - if ( position < key->data.frame ) - { - memset( item, 0, sizeof( struct mlt_geometry_item_s ) ); - item->mix = 100; - } - // Position is a key itself - no iterpolation need - else if ( position == key->data.frame ) - { - memcpy( item, &key->data, sizeof( struct mlt_geometry_item_s ) ); - } - // Position is after the last key - no interpolation, but not a key frame - else if ( key->next == NULL ) - { - memcpy( item, &key->data, sizeof( struct mlt_geometry_item_s ) ); - item->key = 0; - item->f[ 0 ] = 0; - item->f[ 1 ] = 0; - item->f[ 2 ] = 0; - item->f[ 3 ] = 0; - item->f[ 4 ] = 0; - } - // Interpolation is needed - position > key and there is a following key - else - { - item->key = 0; - item->frame = position; - position -= key->data.frame; - item->x = linearstep( key->data.x, key->next->data.x, position, key->next->data.frame - key->data.frame ); - item->y = linearstep( key->data.y, key->next->data.y, position, key->next->data.frame - key->data.frame ); - item->w = linearstep( key->data.w, key->next->data.w, position, key->next->data.frame - key->data.frame ); - item->h = linearstep( key->data.h, key->next->data.h, position, key->next->data.frame - key->data.frame ); - item->mix = linearstep( key->data.mix, key->next->data.mix, position, key->next->data.frame - key->data.frame ); - item->distort = key->data.distort; - position += key->data.frame; - } - - item->frame = position; - } - else - { - memset( item, 0, sizeof( struct mlt_geometry_item_s ) ); - item->frame = position; - item->mix = 100; - } - - return key == NULL; -} - -// Specify a geometry item at an absolute position -int mlt_geometry_insert( mlt_geometry self, mlt_geometry_item item ) -{ - // Get the local/private geometry structure - geometry g = self->local; - - // Create a new local item (this may be removed if a key already exists at self position) - geometry_item gi = calloc( 1, sizeof( struct geometry_item_s ) ); - memcpy( &gi->data, item, sizeof( struct mlt_geometry_item_s ) ); - gi->data.key = 1; - - // Determine if we need to insert or append to the list, or if it's a new list - if ( g->item != NULL ) - { - // Get the first item - geometry_item place = g->item; - - // Locate an existing nearby item - while ( place->next != NULL && item->frame > place->data.frame ) - place = place->next; - - if ( item->frame < place->data.frame ) - { - if ( place == g->item ) - g->item = gi; - if ( place->prev ) - place->prev->next = gi; - gi->next = place; - gi->prev = place->prev; - place->prev = gi; - } - else if ( item->frame > place->data.frame ) - { - if ( place->next ) - place->next->prev = gi; - gi->next = place->next; - gi->prev = place; - place->next = gi; - } - else - { - memcpy( &place->data, &gi->data, sizeof( struct mlt_geometry_item_s ) ); - free( gi ); - } - } - else - { - // Set the first item - g->item = gi; - - // To ensure correct seeding, ensure all values are fixed - g->item->data.f[0] = 1; - g->item->data.f[1] = 1; - g->item->data.f[2] = 1; - g->item->data.f[3] = 1; - g->item->data.f[4] = 1; - } - - // TODO: Error checking - return 0; -} - -// Remove the key at the specified position -int mlt_geometry_remove( mlt_geometry self, int position ) -{ - int ret = 1; - - // Get the local/private geometry structure - geometry g = self->local; - - // Get the first item - geometry_item place = g->item; - - while( place != NULL && position != place->data.frame ) - place = place->next; - - if ( place != NULL && position == place->data.frame ) - ret = mlt_geometry_drop( self, place ); - - return ret; -} - -// Get the key at the position or the next following -int mlt_geometry_next_key( mlt_geometry self, mlt_geometry_item item, int position ) -{ - // Get the local/private geometry structure - geometry g = self->local; - - // Get the first item - geometry_item place = g->item; - - while( place != NULL && position > place->data.frame ) - place = place->next; - - if ( place != NULL ) - memcpy( item, &place->data, sizeof( struct mlt_geometry_item_s ) ); - - return place == NULL; -} - -// Get the key at the position or the previous key -int mlt_geometry_prev_key( mlt_geometry self, mlt_geometry_item item, int position ) -{ - // Get the local/private geometry structure - geometry g = self->local; - - // Get the first item - geometry_item place = g->item; - - while( place != NULL && place->next != NULL && position >= place->next->data.frame ) - place = place->next; - - if ( place != NULL ) - memcpy( item, &place->data, sizeof( struct mlt_geometry_item_s ) ); - - return place == NULL; -} - -char *mlt_geometry_serialise_cut( mlt_geometry self, int in, int out ) -{ - geometry g = self->local; - struct mlt_geometry_item_s item; - char *ret = malloc( 1000 ); - int used = 0; - int size = 1000; - - if ( in == -1 ) - in = 0; - if ( out == -1 ) - out = mlt_geometry_get_length( self ); - - if ( ret != NULL ) - { - char temp[ 100 ]; - - strcpy( ret, "" ); - - item.frame = in; - - while( 1 ) - { - strcpy( temp, "" ); - - // If it's the first frame, then it's not necessarily a key - if ( item.frame == in ) - { - if ( mlt_geometry_fetch( self, &item, item.frame ) ) - break; - - // If the first key is larger than the current position - // then do nothing here - if ( g->item->data.frame > item.frame ) - { - item.frame ++; - continue; - } - - // To ensure correct seeding, ensure all values are fixed - item.f[0] = 1; - item.f[1] = 1; - item.f[2] = 1; - item.f[3] = 1; - item.f[4] = 1; - } - // Typically, we move from key to key - else if ( item.frame < out ) - { - if ( mlt_geometry_next_key( self, &item, item.frame ) ) - break; - - // Special case - crop at the out point - if ( item.frame > out ) - mlt_geometry_fetch( self, &item, out ); - } - // We've handled the last key - else - { - break; - } - - if ( item.frame - in != 0 ) - sprintf( temp, "%d=", item.frame - in ); - - if ( item.f[0] ) - sprintf( temp + strlen( temp ), "%g", item.x ); - if ( item.f[1] ) { - strcat( temp, "/" ); - sprintf( temp + strlen( temp ), "%g", item.y ); - } - if ( item.f[2] ) { - strcat( temp, ":" ); - sprintf( temp + strlen( temp ), "%g", item.w ); - } - if ( item.f[3] ) { - strcat( temp, "x" ); - sprintf( temp + strlen( temp ), "%g", item.h ); - } - if ( item.f[4] ) { - strcat( temp, ":" ); - sprintf( temp + strlen( temp ), "%g", item.mix ); - } - - if ( used + strlen( temp ) + 2 > size ) // +2 for ';' and NULL - { - size += 1000; - ret = realloc( ret, size ); - } - - if ( ret != NULL && used != 0 ) - { - used ++; - strcat( ret, ";" ); - } - if ( ret != NULL ) - { - used += strlen( temp ); - strcat( ret, temp ); - } - - item.frame ++; - } - } - - return ret; -} - -// Serialise the current geometry -char *mlt_geometry_serialise( mlt_geometry self ) -{ - geometry g = self->local; - char *ret = mlt_geometry_serialise_cut( self, 0, g->length ); - if ( ret ) - { - free( g->data ); - g->data = ret; - } - return strdup( ret ); -} - -// Close the geometry -void mlt_geometry_close( mlt_geometry self ) -{ - if ( self != NULL ) - { - mlt_geometry_clean( self ); - free( self->local ); - free( self ); - } -} - - diff --git a/src/framework/mlt_geometry.h b/src/framework/mlt_geometry.h deleted file mode 100644 index c15531e55..000000000 --- a/src/framework/mlt_geometry.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - * \file mlt_geometry.h - * \brief geometry animation API (deprecated) - * \deprecated use mlt_animation_s instead - * - * Copyright (C) 2004-2014 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 MLT_GEOMETRY_H -#define MLT_GEOMETRY_H - -#include "mlt_types.h" - -/** geometry animation item (deprecated) - * \deprecated use mlt_animation_s instead - */ - -struct mlt_geometry_item_s -{ - /* Will be 1 when this is a key frame */ - int key; - /* The actual frame this corresponds to */ - int frame; - /* Distort */ - int distort; - /* x,y are upper left */ - float x, y, w, h, mix; - /* Indicates which values are fixed */ - int f[ 5 ]; -}; - -/** geometry object (deprecated) - * \deprecated use mlt_animation_s instead - */ - -struct mlt_geometry_s -{ - void *local; -}; - -/* Create a new geometry structure */ -extern mlt_geometry mlt_geometry_init( ); -/* Parse the geometry specification for a given length and normalised width/height (-1 for default) */ -extern int mlt_geometry_parse( mlt_geometry self, char *data, int length, int nw, int nh ); -/* Conditionally refresh the geometry if it's modified */ -extern int mlt_geometry_refresh( mlt_geometry self, char *data, int length, int nw, int nh ); -/* Get and set the length */ -extern int mlt_geometry_get_length( mlt_geometry self ); -extern void mlt_geometry_set_length( mlt_geometry self, int length ); -/* Parse an item - doesn't affect the geometry itself but uses current information for evaluation */ -/* (item->frame should be specified if not included in the data itself) */ -extern int mlt_geometry_parse_item( mlt_geometry self, mlt_geometry_item item, char *data ); -/* Fetch a geometry item for an absolute position */ -extern int mlt_geometry_fetch( mlt_geometry self, mlt_geometry_item item, float position ); -/* Specify a geometry item at an absolute position */ -extern int mlt_geometry_insert( mlt_geometry self, mlt_geometry_item item ); -/* Remove the key at the specified position */ -extern int mlt_geometry_remove( mlt_geometry self, int position ); -/* Typically, re-interpolate after a series of insertions or removals. */ -extern void mlt_geometry_interpolate( mlt_geometry self ); -/* Get the key at the position or the next following */ -extern int mlt_geometry_next_key( mlt_geometry self, mlt_geometry_item item, int position ); -extern int mlt_geometry_prev_key( mlt_geometry self, mlt_geometry_item item, int position ); -/* Serialise the current geometry */ -extern char *mlt_geometry_serialise_cut( mlt_geometry self, int in, int out ); -extern char *mlt_geometry_serialise( mlt_geometry self ); -/* Close the geometry */ -extern void mlt_geometry_close( mlt_geometry self ); - -#endif - diff --git a/src/framework/mlt_image.c b/src/framework/mlt_image.c new file mode 100644 index 000000000..37640d212 --- /dev/null +++ b/src/framework/mlt_image.c @@ -0,0 +1,431 @@ +/** + * \file mlt_image.c + * \brief Image class + * \see mlt_mlt_image_s + * + * 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 "mlt_image.h" + +#include "mlt_log.h" + +#include +#include + +/** Allocate a new Image object. + * + * \return a new image object with default values set + */ + +mlt_image mlt_image_new() +{ + mlt_image self = calloc( 1, sizeof(struct mlt_image_s) ); + self->close = free; + return self; +} + +/** Destroy an image object created by mlt_image_new(). + * + * \public \memberof mlt_image_s + * \param self the Image object + */ + +void mlt_image_close( mlt_image self ) +{ + if ( self) + { + if ( self->release_data ) + { + self->release_data( self->data ); + } + if ( self->release_alpha ) + { + self->release_alpha( self->alpha ); + } + if ( self->close ) + { + self->close( self ); + } + } +} + +/** Set the most common values for the image. + * + * Less common values will be set to reasonable defaults. + * + * \public \memberof mlt_image_s + * \param self the Image object + * \param data the buffer that contains the image data + * \param format the image format + * \param width the width of the image + * \param height the height of the image + */ + +void mlt_image_set_values( mlt_image self, void* data, mlt_image_format format, int width, int height ) +{ + self->data = data; + self->format = format; + self->width = width; + self->height = height; + self->colorspace = mlt_colorspace_unspecified; + self->release_data = NULL; + self->release_alpha = NULL; + self->close = NULL; + mlt_image_format_planes( self->format, self->width, self->height, self->data, self->planes, self->strides ); +} + +/** Get the most common values for the image. + * + * \public \memberof mlt_image_s + * \param self the Image object + * \param[out] data the buffer that contains the image data + * \param[out] format the image format + * \param[out] width the width of the image + * \param[out] height the height of the image + */ + +void mlt_image_get_values( mlt_image self, void** data, mlt_image_format* format, int* width, int* height ) +{ + *data = self->data; + *format = self->format; + *width = self->width; + *height = self->height; +} + +/** Allocate the data field based on the other properties of the Image. + * + * If the data field is already set, and a destructor function exists, the data + * will be released. Else, the data pointer will be overwritten without being + * released. + * + * After this function call, the release_data field will be set and can be used + * to release the data when necessary. + * + * \public \memberof mlt_image_s + * \param self the Image object + */ + +void mlt_image_alloc_data( mlt_image self ) +{ + if ( !self ) return; + + if ( self->release_data ) + { + self->release_data( self->data ); + } + + int size = mlt_image_calculate_size( self ); + self->data = mlt_pool_alloc( size ); + self->release_data = mlt_pool_release; + mlt_image_format_planes( self->format, self->width, self->height, self->data, self->planes, self->strides ); +} + +/** Allocate the alpha field based on the other properties of the Image. + * + * If the alpha field is already set, and a destructor function exists, the data + * will be released. Else, the data pointer will be overwritten without being + * released. + * + * After this function call, the release_data field will be set and can be used + * to release the data when necessary. + * + * \public \memberof mlt_image_s + * \param self the Image object + */ + +void mlt_image_alloc_alpha( mlt_image self ) +{ + if ( !self ) return; + + if ( self->release_alpha ) + { + self->release_alpha( self->alpha ); + } + + self->alpha = mlt_pool_alloc( self->width * self->height ); + self->release_alpha = mlt_pool_release; + self->strides[3] = self->width; + self->planes[3] = self->alpha; +} + +/** Calculate the number of bytes needed for the Image data. + * + * \public \memberof mlt_image_s + * \param self the Image object + * \return the number of bytes + */ + +int mlt_image_calculate_size( mlt_image self ) +{ + switch ( self->format ) + { + case mlt_image_rgb: + return self->width * self->height * 3; + case mlt_image_rgba: + return self->width * self->height * 4; + case mlt_image_yuv422: + return self->width * self->height * 2; + case mlt_image_yuv420p: + return self->width * self->height * 3 / 2; + case mlt_image_movit: + case mlt_image_opengl_texture: + return 4; + case mlt_image_yuv422p16: + return 4 * self->width * self->height; + case mlt_image_none: + case mlt_image_invalid: + return 0; + } + return 0; +} + + +/** Get the short name for an image format. + * + * \public \memberof mlt_image_s + * \param format the image format + * \return a string + */ + +const char * mlt_image_format_name( mlt_image_format format ) +{ + switch ( format ) + { + case mlt_image_none: return "none"; + case mlt_image_rgb: return "rgb"; + case mlt_image_rgba: return "rgba"; + case mlt_image_yuv422: return "yuv422"; + case mlt_image_yuv420p: return "yuv420p"; + case mlt_image_movit: return "glsl"; + case mlt_image_opengl_texture: return "opengl_texture"; + case mlt_image_yuv422p16: return "yuv422p16"; + case mlt_image_invalid: return "invalid"; + } + return "invalid"; +} + +/** Get the id of image format from short name. + * + * \public \memberof mlt_image_s + * \param name the image format short name + * \return a image format + */ + +mlt_image_format mlt_image_format_id( const char * name ) +{ + mlt_image_format f; + + for ( f = mlt_image_none; name && f < mlt_image_invalid; f++ ) + { + const char * v = mlt_image_format_name( f ); + if ( !strcmp( v, name ) ) + return f; + } + + return mlt_image_invalid; +} + +/** Fill an image with black. + * + * \public \memberof mlt_image_s + */ +void mlt_image_fill_black( mlt_image self ) +{ + if ( !self->data) return; + + switch( self->format ) + { + case mlt_image_invalid: + case mlt_image_none: + case mlt_image_movit: + case mlt_image_opengl_texture: + return; + case mlt_image_rgb: + case mlt_image_rgba: + { + int size = mlt_image_calculate_size( self ); + memset( self->planes[0], 255, size ); + break; + } + case mlt_image_yuv422: + { + int size = mlt_image_calculate_size( self ); + register uint8_t *p = self->planes[0]; + register uint8_t *q = p + size; + while ( p != NULL && p != q ) + { + *p ++ = 235; + *p ++ = 128; + } + } + break; + case mlt_image_yuv422p16: + { + for ( int plane = 0; plane < 3; plane++ ) + { + uint16_t value = 235 << 8; + size_t width = self->width; + if ( plane > 0 ) + { + value = 128 << 8; + width = self->width / 2; + } + uint16_t* pRow = (uint16_t*)self->planes[plane]; + for ( int i = 0; i < self->height; i++ ) + { + uint16_t* p = pRow; + for ( int j = 0; j < width; j++ ) + { + *p++ = value; + } + pRow += self->strides[plane]; + } + } + } + break; + case mlt_image_yuv420p: + { + memset(self->planes[0], 235, self->height * self->strides[0]); + memset(self->planes[1], 128, self->height * self->strides[1] / 2); + memset(self->planes[2], 128, self->height * self->strides[2] / 2); + } + break; + } +} + +/** Fill an image alpha channel with opaque if it exists. + * + * \public \memberof mlt_image_s + */ +void mlt_image_fill_opaque( mlt_image self ) +{ + if ( !self->data) return; + + if ( self->format == mlt_image_rgba && self->planes[0] != NULL ) + { + for ( int line = 0; line < self->height; line++ ) + { + uint8_t* pLine = self->planes[0] + ( self->strides[0] * line ) + 3; + for ( int pixel = 0; pixel < self->width; pixel++ ) + { + *pLine = 0xff; + *pLine += 4; + } + } + } + else if ( self->planes[3] != NULL ) + { + memset( self->planes[3], 255, self->height * self->strides[3] ); + } +} + +/** Get the number of bytes needed for an image. + * + * \public \memberof mlt_image_s + * \param format the image format + * \param width width of the image in pixels + * \param height height of the image in pixels + * \param[out] bpp the number of bytes per pixel (optional) + * \return the number of bytes + */ +int mlt_image_format_size( mlt_image_format format, int width, int height, int *bpp ) +{ + switch ( format ) + { + case mlt_image_rgb: + if ( bpp ) *bpp = 3; + return width * height * 3; + case mlt_image_rgba: + if ( bpp ) *bpp = 4; + return width * height * 4; + case mlt_image_yuv422: + if ( bpp ) *bpp = 2; + return width * height * 2; + case mlt_image_yuv420p: + if ( bpp ) *bpp = 3 / 2; + return width * height * 3 / 2; + case mlt_image_movit: + case mlt_image_opengl_texture: + if ( bpp ) *bpp = 0; + return 4; + case mlt_image_yuv422p16: + if ( bpp ) *bpp = 0; + return 4 * height * width ; + default: + if ( bpp ) *bpp = 0; + return 0; + } + return 0; +} + +/** Build a planes pointers of image mapping + * + * For proper and unified planar image processing, planes sizes and planes pointers should + * be provides to processing code. + * + * \public \memberof mlt_image_s + * \param format the image format + * \param width width of the image in pixels + * \param height height of the image in pixels + * \param[in] data pointer to allocated image + * \param[out] planes pointers to plane's pointers will be set + * \param[out] strides pointers to plane's strides will be set + */ +void mlt_image_format_planes( mlt_image_format format, int width, int height, void* data, uint8_t* planes[4], int strides[4]) +{ + if ( mlt_image_yuv422p16 == format ) + { + strides[0] = width * 2; + strides[1] = width; + strides[2] = width; + strides[3] = 0; + + planes[0] = (unsigned char*)data; + planes[1] = planes[0] + height * strides[0]; + planes[2] = planes[1] + height * strides[1]; + planes[3] = 0; + } + else if ( mlt_image_yuv420p == format ) + { + strides[0] = width; + strides[1] = width >> 1; + strides[2] = width >> 1; + 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[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[1] = 0; + strides[2] = 0; + strides[3] = 0; + }; +} diff --git a/src/framework/mlt_image.h b/src/framework/mlt_image.h new file mode 100644 index 000000000..2800a0c31 --- /dev/null +++ b/src/framework/mlt_image.h @@ -0,0 +1,65 @@ +/** + * \file mlt_image.h + * \brief Image class + * \see mlt_image_s + * + * Copyright (C) 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 + */ + +#ifndef MLT_IMAGE_H +#define MLT_IMAGE_H + +#include "mlt_types.h" + +/** \brief Image class + * + * Image is the data object that represents image for a period of time. + */ +#define MLT_IMAGE_MAX_PLANES 4 + +struct mlt_image_s +{ + mlt_image_format format; + int width; + int height; + int colorspace; + uint8_t* planes[MLT_IMAGE_MAX_PLANES]; + int strides[MLT_IMAGE_MAX_PLANES]; + void* data; + mlt_destructor release_data; + void* alpha; + mlt_destructor release_alpha; + mlt_destructor close; +}; + +extern mlt_image mlt_image_new(); +extern void mlt_image_close( mlt_image self ); +extern void mlt_image_set_values( mlt_image self, void* data, mlt_image_format format, int width, int height ); +extern void mlt_image_get_values( mlt_image self, void** data, mlt_image_format* format, int* width, int* height ); +extern void mlt_image_alloc_data( mlt_image self ); +extern void mlt_image_alloc_alpha( mlt_image self ); +extern int mlt_image_calculate_size( mlt_image self ); +extern void mlt_image_fill_black( mlt_image self ); +extern void mlt_image_fill_opaque( mlt_image self ); +extern const char * mlt_image_format_name( mlt_image_format format ); +extern mlt_image_format mlt_image_format_id( const char * name ); + +// Deprecated functions +extern int mlt_image_format_size( mlt_image_format format, int width, int height, int *bpp ); +extern void mlt_image_format_planes( mlt_image_format format, int width, int height, void* data, uint8_t* planes[4], int strides[4]); + +#endif diff --git a/src/framework/mlt_link.c b/src/framework/mlt_link.c new file mode 100644 index 000000000..13f340b58 --- /dev/null +++ b/src/framework/mlt_link.c @@ -0,0 +1,168 @@ +/** + * \file mlt_link.c + * \brief link service class + * \see mlt_link_s + * + * Copyright (C) 2020 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 "mlt_link.h" +#include "mlt_frame.h" +#include "mlt_log.h" + +#include +#include + +/* Forward references to static methods. +*/ + +static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int track ); +static int producer_seek( mlt_producer parent, mlt_position position ); +static int producer_set_in_and_out( mlt_producer, mlt_position, mlt_position ); + +/** Construct a link. + * + * Sets the mlt_type to "link" + * + * \public \memberof mlt_link_s + * \return the new link + */ + +mlt_link mlt_link_init( ) +{ + mlt_link self = calloc( 1, sizeof( struct mlt_link_s ) ); + if ( self != NULL ) + { + mlt_producer producer = &self->parent; + if ( mlt_producer_init( producer, self ) == 0 ) + { + mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); + + mlt_properties_set( properties, "mlt_type", "link" ); + mlt_properties_clear( properties, "mlt_service"); + mlt_properties_clear( properties, "resource"); + mlt_properties_clear( properties, "in"); + mlt_properties_clear( properties, "out"); + mlt_properties_clear( properties, "length"); + mlt_properties_clear( properties, "eof"); + producer->get_frame = producer_get_frame; + producer->seek = producer_seek; + producer->set_in_and_out = producer_set_in_and_out; + producer->close = ( mlt_destructor )mlt_link_close; + producer->close_object = self; + } + else + { + free( self ); + self = NULL; + } + } + return self; +} + +/** Connect this link to the next producer. + * + * \public \memberof mlt_link_s + * \param self a link + * \param next the producer to get frames from + * \param chain_profile a profile to use if needed (some links derive their frame rate from the next producer) + * \return true on error + */ + +int mlt_link_connect_next( mlt_link self, mlt_producer next, mlt_profile chain_profile ) +{ + self->next = next; + if ( self->configure ) + { + self->configure( self, chain_profile ); + } + return 0; +} + +/** Close the link and free its resources. + * + * \public \memberof mlt_link_s + * \param self a link + */ + +void mlt_link_close( mlt_link self ) +{ + if ( self != NULL && mlt_properties_dec_ref( MLT_LINK_PROPERTIES( self ) ) <= 0 ) + { + if( self->close ) + { + self->close( self ); + } + else + { + self->parent.close = NULL; + mlt_producer_close( &self->parent ); + } + } +} + +static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ) +{ + if ( parent && parent->child ) + { + mlt_link self = parent->child; + if ( self->get_frame != NULL ) + { + return self->get_frame( self, frame, index ); + } + else + { + /* Default implementation: get a frame from the next producer */ + return mlt_service_get_frame( MLT_PRODUCER_SERVICE( self->next ), frame, index ); + } + } + return 1; +} + +int producer_seek( mlt_producer parent, mlt_position position ) +{ + // Unlike mlt_producer_seek(), a link does not do bounds checking when seeking + if ( parent && parent->child ) + { + mlt_link self = parent->child; + mlt_properties properties = MLT_LINK_PROPERTIES( self ); + int use_points = 1 - mlt_properties_get_int( properties, "ignore_points" ); + + // Set the position + mlt_properties_set_position( properties, "_position", position ); + + // Calculate the absolute frame + mlt_properties_set_position( properties, "_frame", use_points * mlt_producer_get_in( parent ) + position ); + } + return 0; +} + + +int producer_set_in_and_out( mlt_producer parent, mlt_position in, mlt_position out ) +{ + // Unlike mlt_producer_set_in_and_out(), a link does not do bounds checking against length + if ( parent && parent->child ) + { + mlt_link self = parent->child; + mlt_properties properties = MLT_LINK_PROPERTIES( self ); + mlt_events_block( properties, properties ); + mlt_properties_set_position( properties, "in", in ); + mlt_events_unblock( properties, properties ); + mlt_properties_set_position( properties, "out", out ); + } + return 0; +} diff --git a/src/framework/mlt_link.h b/src/framework/mlt_link.h new file mode 100644 index 000000000..802f63853 --- /dev/null +++ b/src/framework/mlt_link.h @@ -0,0 +1,76 @@ +/** + * \file mlt_link.h + * \brief link service class + * \see mlt_link_s + * + * Copyright (C) 2020 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 MLT_LINK_H +#define MLT_LINK_H + +#include "mlt_producer.h" + +/** \brief Link class + * + * The link is a producer class that that can be connected to other link producers in a Chain. + * + * \extends mlt_producer_s + * \properties \em next holds a reference to the next producer in the chain + */ + +struct mlt_link_s +{ + /** \publicsection */ + struct mlt_producer_s parent; + + /** \protectedsection */ + + /** Get a frame of data (virtual function). + * + * \param mlt_link a link + * \param mlt_frame_ptr a frame pointer by reference + * \param int an index + * \return true if there was an error + */ + int ( *get_frame )( mlt_link, mlt_frame_ptr, int ); + + /** Configure the link (virtual function). + * + * \param mlt_link a link + * \param mlt_profile a default profile to use + */ + void ( *configure )( mlt_link, mlt_profile ); + + /** Virtual close function */ + void ( *close )( mlt_link ); + + /** \privatesection */ + mlt_producer next; + /** the object of a subclass */ + void *child; +}; + +#define MLT_LINK_PRODUCER( link ) ( &( link )->parent ) +#define MLT_LINK_SERVICE( link ) MLT_PRODUCER_SERVICE( MLT_LINK_PRODUCER( link ) ) +#define MLT_LINK_PROPERTIES( link ) MLT_SERVICE_PROPERTIES( MLT_LINK_SERVICE( link ) ) + +extern mlt_link mlt_link_init( ); +extern int mlt_link_connect_next( mlt_link self, mlt_producer next, mlt_profile chain_profile ); +extern void mlt_link_close( mlt_link self ); + +#endif diff --git a/src/framework/mlt_parser.c b/src/framework/mlt_parser.c index 105bb427c..0acbec50c 100644 --- a/src/framework/mlt_parser.c +++ b/src/framework/mlt_parser.c @@ -103,6 +103,27 @@ static int on_end_transition( mlt_parser self, mlt_transition object ) return 0; } + +static int on_start_chain( mlt_parser self, mlt_chain object ) +{ + return 0; +} + +static int on_end_chain( mlt_parser self, mlt_chain object ) +{ + return 0; +} + +static int on_start_link( mlt_parser self, mlt_link object ) +{ + return 0; +} + +static int on_end_link( mlt_parser self, mlt_link object ) +{ + return 0; +} + mlt_parser mlt_parser_new( ) { mlt_parser self = calloc( 1, sizeof( struct mlt_parser_s ) ); @@ -124,6 +145,10 @@ mlt_parser mlt_parser_new( ) self->on_end_filter = on_end_filter; self->on_start_transition = on_start_transition; self->on_end_transition = on_end_transition; + self->on_start_chain = on_start_chain; + self->on_end_chain = on_end_chain; + self->on_start_link = on_start_link; + self->on_end_link = on_end_link; } return self; } @@ -139,13 +164,13 @@ int mlt_parser_start( mlt_parser self, mlt_service object ) mlt_service_type type = mlt_service_identify( object ); switch( type ) { - case invalid_type: + case mlt_service_invalid_type: error = self->on_invalid( self, object ); break; - case unknown_type: + case mlt_service_unknown_type: error = self->on_unknown( self, object ); break; - case producer_type: + case mlt_service_producer_type: if ( mlt_producer_is_cut( ( mlt_producer )object ) ) error = mlt_parser_start( self, ( mlt_service )mlt_producer_cut_parent( ( mlt_producer )object ) ); error = self->on_start_producer( self, ( mlt_producer )object ); @@ -157,7 +182,7 @@ int mlt_parser_start( mlt_parser self, mlt_service object ) } error = self->on_end_producer( self, ( mlt_producer )object ); break; - case playlist_type: + case mlt_service_playlist_type: error = self->on_start_playlist( self, ( mlt_playlist )object ); if ( error == 0 ) { @@ -170,7 +195,7 @@ int mlt_parser_start( mlt_parser self, mlt_service object ) } error = self->on_end_playlist( self, ( mlt_playlist )object ); break; - case tractor_type: + case mlt_service_tractor_type: error = self->on_start_tractor( self, ( mlt_tractor )object ); if ( error == 0 ) { @@ -187,7 +212,7 @@ int mlt_parser_start( mlt_parser self, mlt_service object ) } error = self->on_end_tractor( self, ( mlt_tractor )object ); break; - case multitrack_type: + case mlt_service_multitrack_type: error = self->on_start_multitrack( self, ( mlt_multitrack )object ); if ( error == 0 ) { @@ -204,7 +229,7 @@ int mlt_parser_start( mlt_parser self, mlt_service object ) } error = self->on_end_multitrack( self, ( mlt_multitrack )object ); break; - case filter_type: + case mlt_service_filter_type: error = self->on_start_filter( self, ( mlt_filter )object ); if ( error == 0 ) { @@ -214,7 +239,7 @@ int mlt_parser_start( mlt_parser self, mlt_service object ) } error = self->on_end_filter( self, ( mlt_filter )object ); break; - case transition_type: + case mlt_service_transition_type: error = self->on_start_transition( self, ( mlt_transition )object ); if ( error == 0 ) { @@ -224,9 +249,26 @@ int mlt_parser_start( mlt_parser self, mlt_service object ) } error = self->on_end_transition( self, ( mlt_transition )object ); break; - case field_type: + case mlt_service_field_type: + break; + case mlt_service_consumer_type: + break; + case mlt_service_chain_type: + error = self->on_start_chain( self, ( mlt_chain )object ); + if ( error == 0 ) + { + int i = 0; + while ( error == 0 && mlt_chain_link( ( mlt_chain )object, i ) != NULL ) + mlt_parser_start( self, ( mlt_service )mlt_chain_link( ( mlt_chain )object, i ++ ) ); + i = 0; + while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) + error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); + } + error = self->on_end_chain( self, ( mlt_chain )object ); break; - case consumer_type: + case mlt_service_link_type: + error = self->on_start_link( self, ( mlt_link )object ); + error = self->on_end_link( self, ( mlt_link )object ); break; } return error; diff --git a/src/framework/mlt_parser.h b/src/framework/mlt_parser.h index e7e8e7241..ab90a52cd 100644 --- a/src/framework/mlt_parser.h +++ b/src/framework/mlt_parser.h @@ -49,6 +49,10 @@ struct mlt_parser_s int ( *on_end_filter )( mlt_parser self, mlt_filter object ); int ( *on_start_transition )( mlt_parser self, mlt_transition object ); int ( *on_end_transition )( mlt_parser self, mlt_transition object ); + int ( *on_start_chain )( mlt_parser self, mlt_chain object ); + int ( *on_end_chain )( mlt_parser self, mlt_chain object ); + int ( *on_start_link )( mlt_parser self, mlt_link object ); + int ( *on_end_link )( mlt_parser self, mlt_link object ); }; extern mlt_parser mlt_parser_new( ); diff --git a/src/framework/mlt_playlist.c b/src/framework/mlt_playlist.c index a13e5c25b..2593d3228 100644 --- a/src/framework/mlt_playlist.c +++ b/src/framework/mlt_playlist.c @@ -3,7 +3,7 @@ * \brief playlist service class * \see mlt_playlist_s * - * Copyright (C) 2003-2017 Meltytech, LLC + * Copyright (C) 2003-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 @@ -52,7 +52,6 @@ struct playlist_entry_s static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); static int mlt_playlist_unmix( mlt_playlist self, int clip ); static int mlt_playlist_resize_mix( mlt_playlist self, int clip, int in, int out ); -static void mlt_playlist_next( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ); /** Construct a playlist. * @@ -99,7 +98,7 @@ mlt_playlist mlt_playlist_init( ) self->list = calloc( self->size, sizeof( playlist_entry * ) ); if ( self->list == NULL ) goto error2; - mlt_events_register( MLT_PLAYLIST_PROPERTIES( self ), "playlist-next", (mlt_transmitter) mlt_playlist_next ); + mlt_events_register( MLT_PLAYLIST_PROPERTIES( self ), "playlist-next" ); } return self; @@ -395,24 +394,6 @@ static mlt_producer mlt_playlist_locate( mlt_playlist self, mlt_position *positi return producer; } -/** The transmitter for the producer-next event - * - * Invokes the listener. - * - * \private \memberof mlt_playlist_s - * \param listener a function pointer that will be invoked - * \param owner the events object that will be passed to \p listener - * \param self a service that will be passed to \p listener - * \param args an array of pointers. - */ - -static void mlt_playlist_next( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) -{ - if ( listener ) - listener( owner, self, args[ 0 ] ); -} - - /** Seek in the virtual playlist. * * This gets the producer at the current position and seeks on the producer @@ -501,8 +482,9 @@ static mlt_service mlt_playlist_virtual_seek( mlt_playlist self, int *progressiv } // Determine if we have moved to the next entry in the playlist. - if ( original == total - 2 ) - mlt_events_fire( properties, "playlist-next", i, NULL ); + if ( original == total - 2 ) { + mlt_events_fire(properties, "playlist-next", mlt_event_data_from_int(i)); + } return MLT_PRODUCER_SERVICE( producer ); } @@ -2042,25 +2024,6 @@ int mlt_playlist_remove_region( mlt_playlist self, mlt_position position, int le return index; } -/** Not implemented - * - * \deprecated not implemented - * \public \memberof mlt_playlist_s - * \param self - * \param position - * \param length - * \param new_position - * \return - */ - -int mlt_playlist_move_region( mlt_playlist self, mlt_position position, int length, int new_position ) -{ - if ( self != NULL ) - { - } - return 0; -} - /** Get the current frame. * * The implementation of the get_frame virtual function. diff --git a/src/framework/mlt_playlist.h b/src/framework/mlt_playlist.h index b5d813345..20be7bafb 100644 --- a/src/framework/mlt_playlist.h +++ b/src/framework/mlt_playlist.h @@ -66,7 +66,7 @@ typedef struct playlist_entry_s playlist_entry; * 2 to hide the audio (make it a video-only track), or 3 to hide audio and video (hidden track). * This property only applies when using a multitrack or transition. * \event \em playlist-next The playlist fires this when it moves to the next item in the list. - * The listener receives one argument that is the index of the entry that just completed. + * The event data is an integer of the index of the entry that just completed. */ struct mlt_playlist_s @@ -126,7 +126,6 @@ extern int mlt_playlist_clip_start( mlt_playlist self, int clip ); extern int mlt_playlist_clip_length( mlt_playlist self, int clip ); extern int mlt_playlist_blanks_from( mlt_playlist self, int clip, int bounded ); extern int mlt_playlist_remove_region( mlt_playlist self, mlt_position position, int length ); -extern int mlt_playlist_move_region( mlt_playlist self, mlt_position position, int length, int new_position ); extern void mlt_playlist_close( mlt_playlist self ); #endif diff --git a/src/framework/mlt_producer.c b/src/framework/mlt_producer.c index 8cff00664..5a82f6a51 100644 --- a/src/framework/mlt_producer.c +++ b/src/framework/mlt_producer.c @@ -3,7 +3,7 @@ * \brief abstraction for all producer services * \see mlt_producer_s * - * Copyright (C) 2003-2019 Meltytech, LLC + * Copyright (C) 2003-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 @@ -38,7 +38,7 @@ /* Forward references. */ static int producer_get_frame( mlt_service self, mlt_frame_ptr frame, int index ); -static void mlt_producer_property_changed( mlt_service owner, mlt_producer self, char *name ); +static void mlt_producer_property_changed(mlt_service owner, mlt_producer self, mlt_event_data ); static void mlt_producer_service_changed( mlt_service owner, mlt_producer self ); /* for debugging */ @@ -108,7 +108,7 @@ int mlt_producer_init( mlt_producer self, void *child ) mlt_events_listen( properties, self, "service-changed", ( mlt_listener )mlt_producer_service_changed ); mlt_events_listen( properties, self, "property-changed", ( mlt_listener )mlt_producer_property_changed ); - mlt_events_register( properties, "producer-changed", NULL ); + mlt_events_register( properties, "producer-changed" ); } } @@ -125,10 +125,12 @@ int mlt_producer_init( mlt_producer self, void *child ) * \param name the property that changed */ -static void mlt_producer_property_changed( mlt_service owner, mlt_producer self, char *name ) +static void mlt_producer_property_changed( mlt_service owner, mlt_producer self, mlt_event_data event_data) { + const char *name = mlt_event_data_to_string(event_data); + if (!name) return; if ( !strcmp( name, "in" ) || !strcmp( name, "out" ) || !strcmp( name, "length" ) ) - mlt_events_fire( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), "producer-changed", NULL ); + mlt_events_fire( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), "producer-changed", mlt_event_data_none() ); } /** Listener for service changes. @@ -142,7 +144,7 @@ static void mlt_producer_property_changed( mlt_service owner, mlt_producer self, static void mlt_producer_service_changed( mlt_service owner, mlt_producer self ) { - mlt_events_fire( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), "producer-changed", NULL ); + mlt_events_fire( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), "producer-changed", mlt_event_data_none() ); } /** Create and initialize a new producer. @@ -310,6 +312,11 @@ mlt_properties mlt_producer_properties( mlt_producer self ) int mlt_producer_seek( mlt_producer self, mlt_position position ) { + if ( self->seek ) + { + return self->seek( self, position ); + } + // Determine eof handling mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); char *eof = mlt_properties_get( properties, "eof" ); @@ -321,7 +328,11 @@ int mlt_producer_seek( mlt_producer self, mlt_position position ) mlt_producer_seek( mlt_producer_cut_parent( self ), position + mlt_producer_get_in( self ) ); // Check bounds - if ( position < 0 || mlt_producer_get_playtime( self ) == 0 ) + if( mlt_service_identify( MLT_PRODUCER_SERVICE(self) ) == mlt_service_link_type ) + { + // Do not bounds check a link. + } + else if ( position < 0 || mlt_producer_get_playtime( self ) == 0 ) { position = 0; } @@ -454,6 +465,11 @@ double mlt_producer_get_fps( mlt_producer self ) int mlt_producer_set_in_and_out( mlt_producer self, mlt_position in, mlt_position out ) { + if ( self->set_in_and_out ) + { + return self->set_in_and_out( self, in, out ); + } + mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); // Correct ins and outs if necessary @@ -932,7 +948,7 @@ static int on_start_producer( mlt_parser self, mlt_producer object ) mlt_properties properties = mlt_parser_properties( self ); mlt_properties producers = mlt_properties_get_data( properties, "producers", NULL ); mlt_producer parent = mlt_producer_cut_parent( object ); - if ( mlt_service_identify( ( mlt_service )mlt_producer_cut_parent( object ) ) == producer_type && mlt_producer_is_cut( object ) ) + if ( mlt_service_identify( ( mlt_service )mlt_producer_cut_parent( object ) ) == mlt_service_producer_type && mlt_producer_is_cut( object ) ) { int ref_count = 0; clip_references *old_refs = NULL; diff --git a/src/framework/mlt_producer.h b/src/framework/mlt_producer.h index eee87830d..0a9f22f77 100644 --- a/src/framework/mlt_producer.h +++ b/src/framework/mlt_producer.h @@ -80,6 +80,24 @@ struct mlt_producer_s */ int ( *get_frame )( mlt_producer, mlt_frame_ptr, int ); + /** Seek to a specified position (virtual function). + * + * \param mlt_producer a producer + * \param position set the "play head" position of the producer + * \return false + */ + int ( *seek )( mlt_producer, mlt_position ); + + /** Set the in and out points. + * + * \param mlt_producer a producer + * \param mlt_position the relative starting time; a negative value is the same as 0 + * \param mlt_position the relative ending time; a negative value is the same as length - 1 + * \return false + */ + int ( *set_in_and_out )( mlt_producer, mlt_position, mlt_position ); + + /** the destructor virtual function */ mlt_destructor close; void *close_object; /**< the object supplied to the close virtual function */ diff --git a/src/framework/mlt_properties.c b/src/framework/mlt_properties.c index f3e419b57..c8ac9faed 100644 --- a/src/framework/mlt_properties.c +++ b/src/framework/mlt_properties.c @@ -3,7 +3,7 @@ * \brief Properties class definition * \see mlt_properties_s * - * Copyright (C) 2003-2020 Meltytech, LLC + * Copyright (C) 2003-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 @@ -597,6 +597,11 @@ static mlt_property mlt_properties_fetch( mlt_properties self, const char *name return property; } +static void fire_property_changed(mlt_properties self, const char *name) +{ + mlt_events_fire(self, "property-changed", mlt_event_data_from_string(name)); +} + /** Copy a property to another properties list. * * \public \memberof mlt_properties_s @@ -614,7 +619,7 @@ void mlt_properties_pass_property( mlt_properties self, mlt_properties that, con return; mlt_property_pass( mlt_properties_fetch( self, name ), that_prop ); - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); } /** Copy all properties specified in a comma-separated list to another properties list. @@ -786,7 +791,7 @@ int mlt_properties_set( mlt_properties self, const char *name, const char *value mlt_properties_preset( self, value ); } - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); return error; } @@ -848,7 +853,7 @@ int mlt_properties_set_string( mlt_properties self, const char *name, const char mlt_properties_preset( self, value ); } - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); return error; } @@ -1051,7 +1056,7 @@ int mlt_properties_set_int( mlt_properties self, const char *name, int value ) mlt_properties_do_mirror( self, name ); } - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); return error; } @@ -1095,7 +1100,7 @@ int mlt_properties_set_int64( mlt_properties self, const char *name, int64_t val mlt_properties_do_mirror( self, name ); } - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); return error; } @@ -1147,7 +1152,7 @@ int mlt_properties_set_double( mlt_properties self, const char *name, double val mlt_properties_do_mirror( self, name ); } - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); return error; } @@ -1199,7 +1204,7 @@ int mlt_properties_set_position( mlt_properties self, const char *name, mlt_posi mlt_properties_do_mirror( self, name ); } - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); return error; } @@ -1245,7 +1250,7 @@ int mlt_properties_set_data( mlt_properties self, const char *name, void *value, if ( property != NULL ) error = mlt_property_set_data( property, value, length, destroy, serialise ); - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); return error; } @@ -2244,7 +2249,7 @@ void mlt_properties_clear( mlt_properties self, const char *name ) if ( property ) mlt_property_clear( property ); - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); } /** Check if a property exists. @@ -2405,7 +2410,7 @@ int mlt_properties_set_color( mlt_properties self, const char *name, mlt_color c mlt_properties_do_mirror( self, name ); } - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); return error; } @@ -2467,7 +2472,7 @@ int mlt_properties_anim_set( mlt_properties self, const char *name, const char * mlt_properties_do_mirror( self, name ); } - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); return error; } @@ -2525,7 +2530,7 @@ int mlt_properties_anim_set_int( mlt_properties self, const char *name, int valu mlt_properties_do_mirror( self, name ); } - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); return error; } @@ -2583,7 +2588,7 @@ int mlt_properties_anim_set_double( mlt_properties self, const char *name, doubl mlt_properties_do_mirror( self, name ); } - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); return error; } @@ -2627,7 +2632,7 @@ extern int mlt_properties_set_rect( mlt_properties self, const char *name, mlt_r mlt_properties_do_mirror( self, name ); } - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); return error; } @@ -2681,7 +2686,7 @@ extern int mlt_properties_anim_set_rect( mlt_properties self, const char *name, mlt_properties_do_mirror( self, name ); } - mlt_events_fire( self, "property-changed", name, NULL ); + fire_property_changed(self, name); return error; } diff --git a/src/framework/mlt_properties.h b/src/framework/mlt_properties.h index 15772935b..0e2bdf437 100644 --- a/src/framework/mlt_properties.h +++ b/src/framework/mlt_properties.h @@ -31,6 +31,9 @@ * * Properties is a combination list/dictionary of name/::mlt_property pairs. * It is also a base class for many of the other MLT classes. + * + * \event \em property-changed a property's value changed; + * the event data is a string for the name of the property */ struct mlt_properties_s diff --git a/src/framework/mlt_property.c b/src/framework/mlt_property.c index b480bf018..5b02daa18 100644 --- a/src/framework/mlt_property.c +++ b/src/framework/mlt_property.c @@ -3,7 +3,7 @@ * \brief Property class definition * \see mlt_property_s * - * Copyright (C) 2003-2020 Meltytech, LLC + * Copyright (C) 2003-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 @@ -494,8 +494,13 @@ int mlt_property_get_int( mlt_property self, double fps, locale_t locale ) result = ( int )self->prop_int64; else if ( self->types & mlt_prop_rect && self->data ) result = ( int ) ( (mlt_rect*) self->data )->x; - else if ( ( self->types & mlt_prop_string ) && self->prop_string ) - result = mlt_property_atoi( self, fps, locale ); + else + { + if ( self->animation && !mlt_animation_get_string(self->animation) ) + mlt_property_get_string( self ); + if ( ( self->types & mlt_prop_string ) && self->prop_string ) + result = mlt_property_atoi( self, fps, locale ); + } pthread_mutex_unlock( &self->mutex ); return result; } @@ -517,7 +522,7 @@ static double mlt_property_atof( mlt_property self, double fps, locale_t locale { const char *value = self->prop_string; - if ( fps > 0 && strchr( value, ':' ) ) + if ( fps > 0 && strchr( value, ':' ) ) { if ( strchr( value, '.' ) || strchr( value, ',' ) ) return time_clock_to_frames( self, value, fps, locale ); @@ -587,8 +592,13 @@ double mlt_property_get_double( mlt_property self, double fps, locale_t locale ) result = ( double )self->prop_int64; else if ( self->types & mlt_prop_rect && self->data ) result = ( (mlt_rect*) self->data )->x; - else if ( ( self->types & mlt_prop_string ) && self->prop_string ) - result = mlt_property_atof( self, fps, locale ); + else + { + if ( self->animation && !mlt_animation_get_string(self->animation) ) + mlt_property_get_string( self ); + if ( ( self->types & mlt_prop_string ) && self->prop_string ) + result = mlt_property_atof( self, fps, locale ); + } pthread_mutex_unlock( &self->mutex ); return result; } @@ -617,8 +627,13 @@ mlt_position mlt_property_get_position( mlt_property self, double fps, locale_t result = ( mlt_position )self->prop_int64; else if ( self->types & mlt_prop_rect && self->data ) result = ( mlt_position ) ( (mlt_rect*) self->data )->x; - else if ( ( self->types & mlt_prop_string ) && self->prop_string ) - result = ( mlt_position )mlt_property_atoi( self, fps, locale ); + else + { + if ( self->animation && !mlt_animation_get_string(self->animation) ) + mlt_property_get_string( self ); + if ( ( self->types & mlt_prop_string ) && self->prop_string ) + result = ( mlt_position )mlt_property_atoi( self, fps, locale ); + } pthread_mutex_unlock( &self->mutex ); return result; } @@ -662,8 +677,13 @@ int64_t mlt_property_get_int64( mlt_property self ) result = ( int64_t )self->prop_position; else if ( self->types & mlt_prop_rect && self->data ) result = ( int64_t ) ( (mlt_rect*) self->data )->x; - else if ( ( self->types & mlt_prop_string ) && self->prop_string ) - result = mlt_property_atoll( self->prop_string ); + else + { + if ( self->animation && !mlt_animation_get_string(self->animation) ) + mlt_property_get_string( self ); + if ( ( self->types & mlt_prop_string ) && self->prop_string ) + result = mlt_property_atoll( self->prop_string ); + } pthread_mutex_unlock( &self->mutex ); return result; } @@ -1323,6 +1343,15 @@ static void refresh_animation( mlt_property self, double fps, locale_t locale, i self->serialiser = (mlt_serialiser) mlt_animation_serialize_tf; mlt_animation_parse( self->animation, self->prop_string, length, fps, locale ); } + else if ( !mlt_animation_get_string( self->animation ) ) + { + // The animation clears its string if it is modified. + // Do not use a property string that is out of sync. + self->types &= ~mlt_prop_string; + if ( self->prop_string ) + free( self->prop_string ); + self->prop_string = NULL; + } else if ( ( self->types & mlt_prop_string ) && self->prop_string ) { mlt_animation_refresh( self->animation, self->prop_string, length ); @@ -1577,7 +1606,7 @@ mlt_animation mlt_property_get_animation( mlt_property self ) /** Convert a rectangle value into a string. * - * Unlike the deprecated mlt_geometry API, the canonical form of a mlt_rect + * The canonical form of a mlt_rect * is a space delimited "x y w h o" even though many kinds of field delimiters * may be used to convert a string to a rectangle. * \private \memberof mlt_property_s diff --git a/src/framework/mlt_repository.c b/src/framework/mlt_repository.c index 814207393..ce73086d6 100644 --- a/src/framework/mlt_repository.c +++ b/src/framework/mlt_repository.c @@ -47,6 +47,7 @@ struct mlt_repository_s struct mlt_properties_s parent; /// a list of object files mlt_properties consumers; /// a list of entry points for consumers mlt_properties filters; /// a list of entry points for filters + mlt_properties links; /// a list of entry points for links mlt_properties producers; /// a list of entry points for producers mlt_properties transitions; /// a list of entry points for transitions }; @@ -69,6 +70,7 @@ mlt_repository mlt_repository_init( const char *directory ) mlt_properties_init( &self->parent, self ); self->consumers = mlt_properties_new(); self->filters = mlt_properties_new(); + self->links = mlt_properties_new(); self->producers = mlt_properties_new(); self->transitions = mlt_properties_new(); @@ -102,11 +104,6 @@ mlt_repository mlt_repository_init( const char *directory ) int flags = RTLD_NOW; const char *object_name = mlt_properties_get_value( dir, i); - // Very temporary hack to allow the quicktime plugins to work - // TODO: extend repository to allow this to be used on a case by case basis - if ( strstr( object_name, "libmltkino" ) ) - flags |= RTLD_GLOBAL; - // Open the shared object void *object = dlopen( object_name, flags ); if ( object != NULL ) @@ -172,19 +169,23 @@ void mlt_repository_register( mlt_repository self, mlt_service_type service_type // Add the entry point to the corresponding service list switch ( service_type ) { - case consumer_type: + case mlt_service_consumer_type: mlt_properties_set_data( self->consumers, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); break; - case filter_type: + case mlt_service_filter_type: mlt_properties_set_data( self->filters, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); break; - case producer_type: + case mlt_service_link_type: + mlt_properties_set_data( self->links, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); + break; + case mlt_service_producer_type: mlt_properties_set_data( self->producers, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); break; - case transition_type: + case mlt_service_transition_type: mlt_properties_set_data( self->transitions, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); break; default: + mlt_log_error( NULL, "%s: Unable to register \"%s\"\n", __FUNCTION__, service ); break; } } @@ -205,16 +206,19 @@ static mlt_properties get_service_properties( mlt_repository self, mlt_service_t // Get the entry point from the corresponding service list switch ( type ) { - case consumer_type: + case mlt_service_consumer_type: service_properties = mlt_properties_get_data( self->consumers, service, NULL ); break; - case filter_type: + case mlt_service_filter_type: service_properties = mlt_properties_get_data( self->filters, service, NULL ); break; - case producer_type: + case mlt_service_link_type: + service_properties = mlt_properties_get_data( self->links, service, NULL ); + break; + case mlt_service_producer_type: service_properties = mlt_properties_get_data( self->producers, service, NULL ); break; - case transition_type: + case mlt_service_transition_type: service_properties = mlt_properties_get_data( self->transitions, service, NULL ); break; default: @@ -286,6 +290,18 @@ mlt_properties mlt_repository_filters( mlt_repository self ) return self->filters; } +/** Get the list of registered links. + * + * \public \memberof mlt_repository_s + * \param self a repository + * \return a properties list of all of the links + */ + +mlt_properties mlt_repository_links( mlt_repository self ) +{ + return self->links; +} + /** Get the list of registered producers. * * \public \memberof mlt_repository_s diff --git a/src/framework/mlt_repository.h b/src/framework/mlt_repository.h index f004b6d0e..c17cf9610 100644 --- a/src/framework/mlt_repository.h +++ b/src/framework/mlt_repository.h @@ -59,6 +59,7 @@ extern void *mlt_repository_create( mlt_repository self, mlt_profile profile, ml extern void mlt_repository_close( mlt_repository self ); extern mlt_properties mlt_repository_consumers( mlt_repository self ); extern mlt_properties mlt_repository_filters( mlt_repository self ); +extern mlt_properties mlt_repository_links( mlt_repository self ); extern mlt_properties mlt_repository_producers( mlt_repository self ); extern mlt_properties mlt_repository_transitions( mlt_repository self ); extern void mlt_repository_register_metadata( mlt_repository self, mlt_service_type type, const char *service, mlt_metadata_callback, void *callback_data ); diff --git a/src/framework/mlt_service.c b/src/framework/mlt_service.c index 91919d5f9..d7bad47b3 100644 --- a/src/framework/mlt_service.c +++ b/src/framework/mlt_service.c @@ -3,7 +3,7 @@ * \brief interface definition for all service classes * \see mlt_service_s * - * Copyright (C) 2003-2016 Meltytech, LLC + * Copyright (C) 2003-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 @@ -65,7 +65,6 @@ mlt_service_base; static void mlt_service_disconnect( mlt_service self ); static void mlt_service_connect( mlt_service self, mlt_service that ); static int service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ); -static void mlt_service_property_changed( mlt_listener, mlt_properties owner, mlt_service self, void **args ); /** Initialize a service. * @@ -99,31 +98,14 @@ int mlt_service_init( mlt_service self, void *child ) self->parent.close_object = self; mlt_events_init( &self->parent ); - mlt_events_register( &self->parent, "service-changed", NULL ); - mlt_events_register( &self->parent, "property-changed", ( mlt_transmitter )mlt_service_property_changed ); + mlt_events_register( &self->parent, "service-changed" ); + mlt_events_register( &self->parent, "property-changed" ); pthread_mutex_init( &( ( mlt_service_base * )self->local )->mutex, NULL ); } return error; } -/** The transmitter for property changes. - * - * Invokes the listener. - * - * \private \memberof mlt_service_s - * \param listener a function pointer that will be invoked - * \param owner a properties list that will be passed to \p listener - * \param self a service that will be passed to \p listener - * \param args an array of pointers - the first entry is passed as a string to \p listener - */ - -static void mlt_service_property_changed( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) -{ - if ( listener != NULL ) - listener( owner, self, ( char * )args[ 0 ] ); -} - /** Acquire a mutual exclusion lock on this service. * * \public \memberof mlt_service_s @@ -157,32 +139,36 @@ void mlt_service_unlock( mlt_service self ) mlt_service_type mlt_service_identify( mlt_service self ) { - mlt_service_type type = invalid_type; + mlt_service_type type = mlt_service_invalid_type; if ( self != NULL ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( self ); char *mlt_type = mlt_properties_get( properties, "mlt_type" ); char *resource = mlt_properties_get( properties, "resource" ); if ( mlt_type == NULL ) - type = unknown_type; + type = mlt_service_unknown_type; else if (resource != NULL && !strcmp( resource, "" ) ) - type = playlist_type; + type = mlt_service_playlist_type; else if (resource != NULL && !strcmp( resource, "" ) ) - type = tractor_type; + type = mlt_service_tractor_type; else if (resource != NULL && !strcmp( resource, "" ) ) - type = multitrack_type; + type = mlt_service_multitrack_type; else if ( !strcmp( mlt_type, "mlt_producer" ) ) - type = producer_type; + type = mlt_service_producer_type; else if ( !strcmp( mlt_type, "producer" ) ) - type = producer_type; + type = mlt_service_producer_type; else if ( !strcmp( mlt_type, "filter" ) ) - type = filter_type; + type = mlt_service_filter_type; else if ( !strcmp( mlt_type, "transition" ) ) - type = transition_type; + type = mlt_service_transition_type; + else if ( !strcmp( mlt_type, "chain" ) ) + type = mlt_service_chain_type; else if ( !strcmp( mlt_type, "consumer" ) ) - type = consumer_type; + type = mlt_service_consumer_type; + else if ( !strcmp( mlt_type, "link" ) ) + type = mlt_service_link_type; else - type = unknown_type; + type = mlt_service_unknown_type; } return type; } @@ -590,7 +576,7 @@ int mlt_service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ) mlt_properties properties = MLT_SERVICE_PROPERTIES( self ); mlt_position in = mlt_properties_get_position( properties, "in" ); mlt_position out = mlt_properties_get_position( properties, "out" ); - mlt_position position = mlt_service_identify( self ) == producer_type ? mlt_producer_position( MLT_PRODUCER( self ) ) : -1; + mlt_position position = mlt_service_identify( self ) == mlt_service_producer_type ? mlt_producer_position( MLT_PRODUCER( self ) ) : -1; result = self->get_frame( self, frame, index ); @@ -607,7 +593,7 @@ int mlt_service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ) mlt_service_apply_filters( self, *frame, 1 ); mlt_deque_push_back( MLT_FRAME_SERVICE_STACK( *frame ), self ); - if ( mlt_service_identify( self ) == producer_type && + if ( mlt_service_identify( self ) == mlt_service_producer_type && mlt_properties_get_int( MLT_SERVICE_PROPERTIES( self ), "_need_previous_next" ) ) { // Save the new position from self->get_frame @@ -656,7 +642,7 @@ int mlt_service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ) static void mlt_service_filter_changed( mlt_service owner, mlt_service self ) { - mlt_events_fire( MLT_SERVICE_PROPERTIES( self ), "service-changed", NULL ); + mlt_events_fire( MLT_SERVICE_PROPERTIES( self ), "service-changed", mlt_event_data_none() ); } /** The property-changed event handler. @@ -667,9 +653,9 @@ static void mlt_service_filter_changed( mlt_service owner, mlt_service self ) * \param name the name of the property that changed */ -static void mlt_service_filter_property_changed( mlt_service owner, mlt_service self, char *name ) +static void mlt_service_filter_property_changed( mlt_service owner, mlt_service self, mlt_event_data event_data ) { - mlt_events_fire( MLT_SERVICE_PROPERTIES( self ), "property-changed", name, NULL ); + mlt_events_fire(MLT_SERVICE_PROPERTIES(self), "property-changed", event_data); } /** Attach a filter. @@ -707,11 +693,11 @@ int mlt_service_attach( mlt_service self, mlt_filter filter ) mlt_properties_inc_ref( MLT_FILTER_PROPERTIES( filter ) ); base->filters[ base->filter_count ++ ] = filter; mlt_properties_set_data( props, "service", self, 0, NULL, NULL ); - mlt_events_fire( properties, "service-changed", NULL ); - mlt_events_fire( props, "service-changed", NULL ); + mlt_events_fire( properties, "service-changed", mlt_event_data_none() ); + mlt_events_fire( props, "service-changed", mlt_event_data_none() ); mlt_service cp = mlt_properties_get_data( properties, "_cut_parent", NULL ); if ( cp ) - mlt_events_fire( MLT_SERVICE_PROPERTIES(cp), "service-changed", NULL ); + mlt_events_fire( MLT_SERVICE_PROPERTIES(cp), "service-changed", mlt_event_data_none() ); mlt_events_listen( props, self, "service-changed", ( mlt_listener )mlt_service_filter_changed ); mlt_events_listen( props, self, "property-changed", ( mlt_listener )mlt_service_filter_property_changed ); } @@ -753,7 +739,7 @@ int mlt_service_detach( mlt_service self, mlt_filter filter ) base->filter_count --; mlt_events_disconnect( MLT_FILTER_PROPERTIES( filter ), self ); mlt_filter_close( filter ); - mlt_events_fire( properties, "service-changed", NULL ); + mlt_events_fire( properties, "service-changed", mlt_event_data_none() ); } } return error; @@ -811,7 +797,7 @@ int mlt_service_move_filter( mlt_service self, int from, int to ) base->filters[i] = base->filters[i + 1]; } base->filters[to] = filter; - mlt_events_fire( MLT_SERVICE_PROPERTIES(self), "service-changed", NULL ); + mlt_events_fire( MLT_SERVICE_PROPERTIES(self), "service-changed", mlt_event_data_none() ); error = 0; } } diff --git a/src/framework/mlt_service.h b/src/framework/mlt_service.h index 7442a7ee5..80219d532 100644 --- a/src/framework/mlt_service.h +++ b/src/framework/mlt_service.h @@ -39,7 +39,7 @@ * a filter graph or what gstreamer calls an element pipeline. * * \event \em service-changed a filter was attached or detached or a transition was connected or disconnected - * \event \em property-changed + * \event \em property-changed a property's value changed; the event data is a string for the name of the property * \properties \em mlt_type identifies the subclass * \properties \em _mlt_service_hidden a flag that indicates whether to hide the mlt_service * \properties \em mlt_service is the name of the implementation of the service @@ -47,7 +47,7 @@ * \properties \em in when to start, what is started is service-specific * \properties \em out when to stop * \properties \em _filter_private Set this on a service to ensure that attached filters are handled privately. - * See modules/core/filter_region.c and modules/core/filter_watermark.c for examples. + * See modules/core/filter_watermark.c for example. * \properties \em _profile stores the mlt_profile for a service * \properties \em _unique_id is a unique identifier * \properties \em _need_previous_next boolean that instructs producers to get diff --git a/src/framework/mlt_slices.c b/src/framework/mlt_slices.c index 60b17cd40..77e3cc101 100644 --- a/src/framework/mlt_slices.c +++ b/src/framework/mlt_slices.c @@ -3,7 +3,7 @@ * \brief sliced threading processing helper * \see mlt_slices_s * - * Copyright (C) 2016-2017 Meltytech, LLC + * Copyright (C) 2016-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 @@ -135,15 +135,14 @@ static void* mlt_slices_worker( void* p ) /** Initialize a sliced threading context * - * \public \memberof mlt_slices_s - * \deprecated + * \private \memberof mlt_slices_s * \param threads number of threads to use for job list, 0 for #cpus * \param policy scheduling policy of processing threads, -1 for normal * \param priority priority value that can be used with the scheduling algorithm, -1 for maximum * \return the context pointer */ -mlt_slices mlt_slices_init( int threads, int policy, int priority ) +static mlt_slices mlt_slices_init( int threads, int policy, int priority ) { pthread_attr_t tattr; struct sched_param param; @@ -219,12 +218,11 @@ mlt_slices mlt_slices_init( int threads, int policy, int priority ) /** Destroy sliced threading context * - * \public \memberof mlt_slices_s - * \deprecated + * \private \memberof mlt_slices_s * \param ctx context pointer */ -void mlt_slices_close( mlt_slices ctx ) +static void mlt_slices_close( mlt_slices ctx ) { int j; @@ -264,14 +262,13 @@ void mlt_slices_close( mlt_slices ctx ) /** Run sliced execution * - * \public \memberof mlt_slices_s - * \deprecated + * \private \memberof mlt_slices_s * \param ctx context pointer * \param jobs number of jobs to process * \param proc number of jobs to process */ -void mlt_slices_run( mlt_slices ctx, int jobs, mlt_slices_proc proc, void* cookie ) +static void mlt_slices_run( mlt_slices ctx, int jobs, mlt_slices_proc proc, void* cookie ) { struct mlt_slices_runtime_s runtime, *r = &runtime; diff --git a/src/framework/mlt_slices.h b/src/framework/mlt_slices.h index 25ffd4404..ad4b2ebce 100644 --- a/src/framework/mlt_slices.h +++ b/src/framework/mlt_slices.h @@ -3,7 +3,7 @@ * \brief sliced threading processing helper * \see mlt_slices_s * - * Copyright (C) 2016-2017 Meltytech, LLC + * Copyright (C) 2016-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 @@ -34,12 +34,6 @@ struct mlt_slices_s; typedef int (*mlt_slices_proc)( int id, int idx, int jobs, void* cookie ); -extern mlt_slices mlt_slices_init( int threads, int policy, int priority ); - -extern void mlt_slices_close( mlt_slices ctx ); - -extern void mlt_slices_run( mlt_slices ctx, int jobs, mlt_slices_proc proc, void* cookie ); - extern int mlt_slices_count_normal(); extern int mlt_slices_count_rr(); diff --git a/src/framework/mlt_tractor.c b/src/framework/mlt_tractor.c index 74a53bc9e..b55323614 100644 --- a/src/framework/mlt_tractor.c +++ b/src/framework/mlt_tractor.c @@ -267,7 +267,7 @@ int mlt_tractor_insert_track( mlt_tractor self, mlt_producer producer, int index mlt_service_type type = mlt_service_identify( service ); mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); - if ( type == transition_type ) + if ( type == mlt_service_transition_type ) { mlt_transition transition = MLT_TRANSITION( service ); int a_track = mlt_transition_get_a_track( transition ); @@ -280,7 +280,7 @@ int mlt_tractor_insert_track( mlt_tractor self, mlt_producer producer, int index mlt_transition_set_tracks( transition, a_track, b_track ); } } - else if ( type == filter_type ) + else if ( type == mlt_service_filter_type ) { int current_track = mlt_properties_get_int( properties, "track" ); if ( current_track >= index ) @@ -313,7 +313,7 @@ int mlt_tractor_remove_track( mlt_tractor self, int index ) mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); int track_max = MAX( mlt_multitrack_count( mlt_tractor_multitrack( self ) ) - 1, 0 ); - if ( type == transition_type ) + if ( type == mlt_service_transition_type ) { mlt_transition transition = MLT_TRANSITION( service ); int a_track = mlt_transition_get_a_track( transition ); @@ -326,7 +326,7 @@ int mlt_tractor_remove_track( mlt_tractor self, int index ) mlt_transition_set_tracks( transition, a_track, b_track ); } } - else if ( type == filter_type ) + else if ( type == mlt_service_filter_type ) { int current_track = mlt_properties_get_int( properties, "track" ); if ( current_track >= index ) @@ -425,22 +425,6 @@ static int producer_get_audio( mlt_frame self, void **buffer, mlt_audio_format * return 0; } -static void destroy_data_queue( void *arg ) -{ - if ( arg != NULL ) - { - // Assign the correct type - mlt_deque queue = arg; - - // Iterate through each item and destroy them - while ( mlt_deque_peek_front( queue ) != NULL ) - mlt_properties_close( mlt_deque_pop_back( queue ) ); - - // Close the deque - mlt_deque_close( queue ); - } -} - /** Get the next frame. * * \private \memberof mlt_tractor_s @@ -472,15 +456,9 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int tra // Or a specific producer mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); - // Determine whether this tractor feeds to the consumer or stops here - int global_feed = mlt_properties_get_int( properties, "global_feed" ); - // If we don't have one, we're in trouble... if ( multitrack != NULL ) { - // The output frame will hold the 'global' data feeds (ie: those which are targeted for the final frame) - mlt_deque data_queue = mlt_deque_init( ); - // Used to garbage collect all frames char label[64]; @@ -554,36 +532,6 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int tra snprintf( label, sizeof(label), "mlt_tractor %s_%d", id, count ++ ); mlt_properties_set_data( frame_properties, label, temp, 0, ( mlt_destructor )mlt_frame_close, NULL ); - // We want to append all 'final' feeds to the global queue - if ( !done && mlt_properties_get_data( temp_properties, "data_queue", NULL ) != NULL ) - { - // Move the contents of this queue on to the output frames data queue - mlt_deque sub_queue = mlt_properties_get_data( MLT_FRAME_PROPERTIES( temp ), "data_queue", NULL ); - mlt_deque temp = mlt_deque_init( ); - while ( global_feed && mlt_deque_count( sub_queue ) ) - { - mlt_properties p = mlt_deque_pop_back( sub_queue ); - if ( mlt_properties_get_int( p, "final" ) ) - mlt_deque_push_back( data_queue, p ); - else - mlt_deque_push_back( temp, p ); - } - while( mlt_deque_count( temp ) ) - mlt_deque_push_front( sub_queue, mlt_deque_pop_back( temp ) ); - mlt_deque_close( temp ); - } - - // Now do the same with the global queue but without the conditional behaviour - if ( mlt_properties_get_data( temp_properties, "global_queue", NULL ) != NULL ) - { - mlt_deque sub_queue = mlt_properties_get_data( MLT_FRAME_PROPERTIES( temp ), "global_queue", NULL ); - while ( mlt_deque_count( sub_queue ) ) - { - mlt_properties p = mlt_deque_pop_back( sub_queue ); - mlt_deque_push_back( data_queue, p ); - } - } - // Pick up first video and audio frames if ( !done && !mlt_frame_is_test_audio( temp ) && !( mlt_properties_get_int( temp_properties, "hide" ) & 2 ) ) { @@ -623,9 +571,6 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int tra mlt_properties video_properties = MLT_FRAME_PROPERTIES( first_video ); mlt_frame_push_service( *frame, video ); mlt_frame_push_service( *frame, producer_get_image ); - if ( global_feed ) - mlt_properties_set_data( frame_properties, "data_queue", data_queue, 0, NULL, NULL ); - mlt_properties_set_data( video_properties, "global_queue", data_queue, 0, destroy_data_queue, NULL ); mlt_properties_set_int( frame_properties, "width", mlt_properties_get_int( video_properties, "width" ) ); mlt_properties_set_int( frame_properties, "height", mlt_properties_get_int( video_properties, "height" ) ); mlt_properties_pass_list( frame_properties, video_properties, "meta.media.width, meta.media.height" ); @@ -634,10 +579,6 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int tra mlt_properties_set_int( frame_properties, "image_count", image_count ); mlt_properties_set_data( frame_properties, "_producer", mlt_frame_get_original_producer( first_video ), 0, NULL, NULL ); } - else - { - destroy_data_queue( data_queue ); - } mlt_frame_set_position( *frame, mlt_producer_frame( parent ) ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_audio", audio == NULL ); diff --git a/src/framework/mlt_tractor.h b/src/framework/mlt_tractor.h index 8b23418e1..0188adeed 100644 --- a/src/framework/mlt_tractor.h +++ b/src/framework/mlt_tractor.h @@ -34,9 +34,6 @@ * \properties \em multitrack holds a reference to the mulitrack object that a tractor manages * \properties \em field holds a reference to the field object that a tractor manages * \properties \em producer holds a reference to an encapsulated producer - * \properties \em global_feed a flag to indicate whether this tractor feeds to the consumer or stops here - * \properties \em global_queue is something for the data_feed functionality in the core module - * \properties \em data_queue is something for the data_feed functionality in the core module */ struct mlt_tractor_s diff --git a/src/framework/mlt_types.h b/src/framework/mlt_types.h index 6e10df973..d1dfd768a 100644 --- a/src/framework/mlt_types.h +++ b/src/framework/mlt_types.h @@ -44,15 +44,14 @@ extern "C" typedef enum { - mlt_image_none = 0,/**< image not available */ - mlt_image_rgb24, /**< 8-bit RGB */ - mlt_image_rgb24a, /**< 8-bit RGB with alpha channel */ - mlt_image_yuv422, /**< 8-bit YUV 4:2:2 packed */ - mlt_image_yuv420p, /**< 8-bit YUV 4:2:0 planar */ - mlt_image_opengl, /**< (deprecated) suitable for OpenGL texture */ - mlt_image_glsl, /**< for opengl module internal use only */ - mlt_image_glsl_texture, /**< an OpenGL texture name */ - mlt_image_yuv422p16, /**< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian */ + mlt_image_none = 0, /**< image not available */ + mlt_image_rgb, /**< 8-bit RGB */ + mlt_image_rgba, /**< 8-bit RGB with alpha channel */ + mlt_image_yuv422, /**< 8-bit YUV 4:2:2 packed */ + mlt_image_yuv420p, /**< 8-bit YUV 4:2:0 planar */ + mlt_image_movit, /**< for movit module internal use only */ + mlt_image_opengl_texture, /**< an OpenGL texture name */ + mlt_image_yuv422p16, /**< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian */ mlt_image_invalid } mlt_image_format; @@ -62,7 +61,6 @@ mlt_image_format; typedef enum { mlt_audio_none = 0,/**< audio not available */ - mlt_audio_pcm = 1, /**< \deprecated signed 16-bit interleaved PCM */ mlt_audio_s16 = 1, /**< signed 16-bit interleaved PCM */ mlt_audio_s32, /**< signed 32-bit non-interleaved PCM */ mlt_audio_float, /**< 32-bit non-interleaved floating point */ @@ -104,6 +102,25 @@ typedef enum } mlt_channel_layout; +/** Colorspace definitions */ + +typedef enum +{ + mlt_colorspace_rgb = 0, ///< order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB) + mlt_colorspace_bt709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B + mlt_colorspace_unspecified = 2, + mlt_colorspace_reserved = 3, + mlt_colorspace_fcc = 4, ///< FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + mlt_colorspace_bt470bg = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601 + mlt_colorspace_smpte170m = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + mlt_colorspace_smpte240m = 7, ///< functionally identical to above + mlt_colorspace_ycgco = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16 + mlt_colorspace_bt2020_ncl = 9, ///< ITU-R BT2020 non-constant luminance system + mlt_colorspace_bt2020_cl = 10, ///< ITU-R BT2020 constant luminance system + mlt_colorspace_smpte2085 = 11, ///< SMPTE 2085, Y'D'zD'x +} +mlt_colorspace; + /** The time string formats */ typedef enum @@ -111,7 +128,6 @@ typedef enum mlt_time_frames = 0, /**< frame count */ mlt_time_clock, /**< SMIL clock-value as [[hh:]mm:]ss[.fraction] */ mlt_time_smpte_df, /**< SMPTE timecode as [[[hh:]mm:]ss{:|;}]frames */ - mlt_time_smpte = mlt_time_smpte_df, /**< Deprecated */ mlt_time_smpte_ndf /**< SMPTE NDF timecode as [[[hh:]mm:]ss:]frames */ } mlt_time_format; @@ -139,16 +155,18 @@ mlt_whence; typedef enum { - invalid_type = 0, /**< invalid service */ - unknown_type, /**< unknown class */ - producer_type, /**< Producer class */ - tractor_type, /**< Tractor class */ - playlist_type, /**< Playlist class */ - multitrack_type, /**< Multitrack class */ - filter_type, /**< Filter class */ - transition_type, /**< Transition class */ - consumer_type, /**< Consumer class */ - field_type /**< Field class */ + mlt_service_invalid_type = 0, /**< invalid service */ + mlt_service_unknown_type, /**< unknown class */ + mlt_service_producer_type, /**< Producer class */ + mlt_service_tractor_type, /**< Tractor class */ + mlt_service_playlist_type, /**< Playlist class */ + mlt_service_multitrack_type, /**< Multitrack class */ + mlt_service_filter_type, /**< Filter class */ + mlt_service_transition_type, /**< Transition class */ + mlt_service_consumer_type, /**< Consumer class */ + mlt_service_field_type, /**< Field class */ + mlt_service_link_type, /**< Link class */ + mlt_service_chain_type /**< Chain class */ } mlt_service_type; @@ -185,6 +203,7 @@ typedef struct { mlt_color; typedef struct mlt_audio_s *mlt_audio; /**< pointer to Audio object */ +typedef struct mlt_image_s *mlt_image; /**< pointer to Image object */ typedef struct mlt_frame_s *mlt_frame, **mlt_frame_ptr; /**< pointer to Frame object */ typedef struct mlt_property_s *mlt_property; /**< pointer to Property object */ typedef struct mlt_properties_s *mlt_properties; /**< pointer to Properties object */ @@ -208,9 +227,12 @@ typedef struct mlt_cache_s *mlt_cache; /**< pointer to Cache ob typedef struct mlt_cache_item_s *mlt_cache_item; /**< pointer to CacheItem object */ typedef struct mlt_animation_s *mlt_animation; /**< pointer to Property Animation object */ typedef struct mlt_slices_s *mlt_slices; /**< pointer to Sliced processing context object */ +typedef struct mlt_link_s *mlt_link; /**< pointer to Link object */ +typedef struct mlt_chain_s *mlt_chain; /**< pointer to Chain object */ typedef void ( *mlt_destructor )( void * ); /**< pointer to destructor function */ typedef char *( *mlt_serialiser )( void *, int length );/**< pointer to serialization function */ +typedef void *( *mlt_thread_function_t )( void* ); /**< generic thread function pointer */ #define MLT_SERVICE(x) ( ( mlt_service )( x ) ) /**< Cast to a Service pointer */ #define MLT_PRODUCER(x) ( ( mlt_producer )( x ) ) /**< Cast to a Producer pointer */ @@ -221,6 +243,8 @@ typedef char *( *mlt_serialiser )( void *, int length );/**< pointer to serializ #define MLT_TRANSITION(x) ( ( mlt_transition )( x ) ) /**< Cast to a Transition pointer */ #define MLT_CONSUMER(x) ( ( mlt_consumer )( x ) ) /**< Cast to a Consumer pointer */ #define MLT_FRAME(x) ( ( mlt_frame )( x ) ) /**< Cast to a Frame pointer */ +#define MLT_LINK(x) ( ( mlt_link )( x ) ) /**< Cast to a Link pointer */ +#define MLT_CHAIN(x) ( ( mlt_chain )( x ) ) /**< Cast to a Chain pointer */ #ifndef MIN #define MIN(x, y) ((x) < (y) ? (x) : (y)) diff --git a/src/framework/mlt_version.h b/src/framework/mlt_version.h index 3b559503a..2bf0bed8d 100644 --- a/src/framework/mlt_version.h +++ b/src/framework/mlt_version.h @@ -26,9 +26,9 @@ #define MLT_STRINGIZE2(s) #s #define MLT_STRINGIZE(s) MLT_STRINGIZE2(s) -#define LIBMLT_VERSION_MAJOR 6 -#define LIBMLT_VERSION_MINOR 26 -#define LIBMLT_VERSION_REVISION 1 +#define LIBMLT_VERSION_MAJOR 7 +#define LIBMLT_VERSION_MINOR 0 +#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 --git a/src/melt/CMakeLists.txt b/src/melt/CMakeLists.txt index 760e9ad16..921edd06e 100644 --- a/src/melt/CMakeLists.txt +++ b/src/melt/CMakeLists.txt @@ -1,14 +1,28 @@ add_executable(melt melt.c io.c) -target_link_libraries(melt mlt Threads::Threads) + +target_compile_options(melt PRIVATE ${MLT_COMPILE_OPTIONS}) + +target_link_libraries(melt PRIVATE mlt Threads::Threads) + target_compile_definitions(melt PRIVATE VERSION="${MLT_VERSION}") if(TARGET PkgConfig::sdl2) - add_library(sdl2 ALIAS PkgConfig::sdl2) - target_link_libraries(melt sdl2) + target_link_libraries(melt PRIVATE PkgConfig::sdl2) target_compile_definitions(melt PRIVATE HAVE_SDL2) if(MINGW) - target_link_libraries(melt mingw32) + target_link_libraries(melt PRIVATE mingw32) endif() endif() -install(TARGETS melt RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +if(MINGW) + 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(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink melt-${MLT_VERSION_MAJOR} melt \ + WORKING_DIRECTORY ${CMAKE_INSTALL_FULL_BINDIR})" + ) +endif() diff --git a/src/melt/melt.c b/src/melt/melt.c index dad5c4a3e..f77aefeea 100644 --- a/src/melt/melt.c +++ b/src/melt/melt.c @@ -57,6 +57,11 @@ static void abnormal_exit_handler(int signum) raise( signum ); } +static void fire_jack_seek_event(mlt_properties jack, int position) +{ + mlt_events_fire(jack, "jack-seek", mlt_event_data_from_int(position)); +} + static void transport_action( mlt_producer producer, char *value ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); @@ -74,14 +79,14 @@ static void transport_action( mlt_producer producer, char *value ) case 'q': case 'Q': mlt_properties_set_int( properties, "done", 1 ); - mlt_events_fire( jack, "jack-stop", NULL ); + mlt_events_fire( jack, "jack-stop", mlt_event_data_none() ); break; case '0': position = 0; mlt_producer_set_speed( producer, 1 ); mlt_producer_seek( producer, position ); mlt_consumer_purge( consumer ); - mlt_events_fire( jack, "jack-seek", &position, NULL ); + fire_jack_seek_event(jack, position); break; case '1': mlt_producer_set_speed( producer, -10 ); @@ -99,14 +104,14 @@ static void transport_action( mlt_producer producer, char *value ) mlt_producer_set_speed( producer, 0 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, mlt_consumer_position( consumer ) + 1 ); - mlt_events_fire( jack, "jack-stop", NULL ); + mlt_events_fire( jack, "jack-stop", mlt_event_data_none() ); break; case '6': case ' ': if ( !jack || mlt_producer_get_speed( producer ) != 0 ) mlt_producer_set_speed( producer, 1 ); mlt_consumer_purge( consumer ); - mlt_events_fire( jack, "jack-start", NULL ); + mlt_events_fire( jack, "jack-start", mlt_event_data_none() ); break; case '7': mlt_producer_set_speed( producer, 2 ); @@ -140,7 +145,7 @@ static void transport_action( mlt_producer producer, char *value ) position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 0 ); mlt_producer_seek( producer, position ); mlt_consumer_purge( consumer ); - mlt_events_fire( jack, "jack-seek", &position, NULL ); + fire_jack_seek_event(jack, position); } break; case 'H': @@ -149,7 +154,7 @@ static void transport_action( mlt_producer producer, char *value ) position -= mlt_producer_get_fps( producer ) * 60; mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); - mlt_events_fire( jack, "jack-seek", &position, NULL ); + fire_jack_seek_event(jack, position); } break; case 'h': @@ -159,8 +164,8 @@ static void transport_action( mlt_producer producer, char *value ) mlt_producer_set_speed( producer, 0 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); - mlt_events_fire( jack, "jack-stop", NULL ); - mlt_events_fire( jack, "jack-seek", &position, NULL ); + mlt_events_fire( jack, "jack-stop", mlt_event_data_none() ); + fire_jack_seek_event(jack, position); } break; case 'j': @@ -169,7 +174,7 @@ static void transport_action( mlt_producer producer, char *value ) position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 1 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); - mlt_events_fire( jack, "jack-seek", &position, NULL ); + fire_jack_seek_event(jack, position); } break; case 'k': @@ -178,7 +183,7 @@ static void transport_action( mlt_producer producer, char *value ) position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, -1 ); mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); - mlt_events_fire( jack, "jack-seek", &position, NULL ); + fire_jack_seek_event(jack, position); } break; case 'l': @@ -189,12 +194,12 @@ static void transport_action( mlt_producer producer, char *value ) if ( mlt_producer_get_speed( producer ) != 0 ) { mlt_producer_set_speed( producer, 0 ); - mlt_events_fire( jack, "jack-stop", NULL ); + mlt_events_fire( jack, "jack-stop", mlt_event_data_none() ); } else { mlt_producer_seek( producer, position ); - mlt_events_fire( jack, "jack-seek", &position, NULL ); + fire_jack_seek_event(jack, position); } } break; @@ -204,7 +209,7 @@ static void transport_action( mlt_producer producer, char *value ) position += mlt_producer_get_fps( producer ) * 60; mlt_consumer_purge( consumer ); mlt_producer_seek( producer, position ); - mlt_events_fire( jack, "jack-seek", &position, NULL ); + fire_jack_seek_event(jack, position); } break; } @@ -215,7 +220,7 @@ static void transport_action( mlt_producer producer, char *value ) mlt_properties_set_int( properties, "stats_off", 0 ); } -static void on_jack_started( mlt_properties owner, mlt_consumer consumer, mlt_position *position ) +static void on_jack_started( mlt_properties owner, mlt_consumer consumer, mlt_event_data event_data ) { mlt_producer producer = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "transport_producer", NULL ); if ( producer ) @@ -223,26 +228,28 @@ static void on_jack_started( mlt_properties owner, mlt_consumer consumer, mlt_po if ( mlt_producer_get_speed( producer ) != 0 ) { mlt_properties jack = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES( consumer ), "jack_filter", NULL ); - mlt_events_fire( jack, "jack-stop", NULL ); + mlt_events_fire( jack, "jack-stop", mlt_event_data_none() ); } else { + mlt_position position = mlt_event_data_to_int(event_data); mlt_producer_set_speed( producer, 1 ); mlt_consumer_purge( consumer ); - mlt_producer_seek( producer, *position ); + mlt_producer_seek( producer, position ); mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 ); } } } -static void on_jack_stopped( mlt_properties owner, mlt_consumer consumer, mlt_position *position ) +static void on_jack_stopped( mlt_properties owner, mlt_consumer consumer, mlt_event_data event_data ) { mlt_producer producer = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "transport_producer", NULL ); if ( producer ) { + mlt_position position = mlt_event_data_to_int(event_data); mlt_producer_set_speed( producer, 0 ); mlt_consumer_purge( consumer ); - mlt_producer_seek( producer, *position ); + mlt_producer_seek( producer, position ); mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 ); } } @@ -495,6 +502,7 @@ static void show_usage( char *program_name ) " -attach-clip filter[:arg] [name=value]* Attach a filter to a producer\n" " -audio-track | -hide-video Add an audio-only track\n" " -blank frames Add blank silence to a track\n" +" -chain id[:arg] [name=value]* Add a producer as a chain\n" " -consumer id[:arg] [name=value]* Set the consumer (sink)\n" " -debug Set the logging level to debug\n" " -filter filter[:arg] [name=value]* Add a filter to the current track\n" @@ -503,6 +511,7 @@ static void show_usage( char *program_name ) " -help Show this message\n" " -jack Enable JACK transport synchronization\n" " -join clips Join multiple clips into one cut\n" +" -link id[:arg] [name=value]* Add a link to a chain\n" " -mix length Add a mix between the last two cuts\n" " -mixer transition Add a transition to the mix\n" " -null-track | -hide-track Add a hidden track\n" @@ -582,19 +591,19 @@ static void query_services( mlt_repository repo, mlt_service_type type ) const char *typestr = NULL; switch ( type ) { - case consumer_type: + case mlt_service_consumer_type: services = mlt_repository_consumers( repo ); typestr = "consumers"; break; - case filter_type: + case mlt_service_filter_type: services = mlt_repository_filters( repo ); typestr = "filters"; break; - case producer_type: + case mlt_service_producer_type: services = mlt_repository_producers( repo ); typestr = "producers"; break; - case transition_type: + case mlt_service_transition_type: services = mlt_repository_transitions( repo ); typestr = "transitions"; break; @@ -809,13 +818,13 @@ int main( int argc, char **argv ) if ( pname && pname[0] != '-' ) { if ( !strcmp( pname, "consumers" ) || !strcmp( pname, "consumer" ) ) - query_services( repo, consumer_type ); + query_services( repo, mlt_service_consumer_type ); else if ( !strcmp( pname, "filters" ) || !strcmp( pname, "filter" ) ) - query_services( repo, filter_type ); + query_services( repo, mlt_service_filter_type ); else if ( !strcmp( pname, "producers" ) || !strcmp( pname, "producer" ) ) - query_services( repo, producer_type ); + query_services( repo, mlt_service_producer_type ); else if ( !strcmp( pname, "transitions" ) || !strcmp( pname, "transition" ) ) - query_services( repo, transition_type ); + query_services( repo, mlt_service_transition_type ); else if ( !strcmp( pname, "profiles" ) || !strcmp( pname, "profile" ) ) query_profiles(); else if ( !strcmp( pname, "presets" ) || !strcmp( pname, "preset" ) ) @@ -828,13 +837,13 @@ int main( int argc, char **argv ) query_vcodecs(); else if ( !strncmp( pname, "consumer=", 9 ) ) - query_metadata( repo, consumer_type, "consumer", strchr( pname, '=' ) + 1 ); + query_metadata( repo, mlt_service_consumer_type, "consumer", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "filter=", 7 ) ) - query_metadata( repo, filter_type, "filter", strchr( pname, '=' ) + 1 ); + query_metadata( repo, mlt_service_filter_type, "filter", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "producer=", 9 ) ) - query_metadata( repo, producer_type, "producer", strchr( pname, '=' ) + 1 ); + query_metadata( repo, mlt_service_producer_type, "producer", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "transition=", 11 ) ) - query_metadata( repo, transition_type, "transition", strchr( pname, '=' ) + 1 ); + query_metadata( repo, mlt_service_transition_type, "transition", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "profile=", 8 ) ) query_profile( strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "preset=", 7 ) ) @@ -845,10 +854,10 @@ int main( int argc, char **argv ) else { query_all: - query_services( repo, consumer_type ); - query_services( repo, filter_type ); - query_services( repo, producer_type ); - query_services( repo, transition_type ); + query_services( repo, mlt_service_consumer_type ); + query_services( repo, mlt_service_filter_type ); + query_services( repo, mlt_service_producer_type ); + query_services( repo, mlt_service_transition_type ); fprintf( stdout, "# You can query the metadata for a specific service using:\n" "# -query =\n" "# where is one of: consumer, filter, producer, or transition.\n" ); @@ -1082,7 +1091,7 @@ int main( int argc, char **argv ) error = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "melt_error" ); mlt_consumer_connect( consumer, NULL ); if ( !is_abort ) - mlt_events_fire( MLT_CONSUMER_PROPERTIES(consumer), "consumer-cleanup", NULL); + mlt_events_fire( MLT_CONSUMER_PROPERTIES(consumer), "consumer-cleanup", mlt_event_data_none()); } if ( is_abort ) diff --git a/src/mlt++/CMakeLists.txt b/src/mlt++/CMakeLists.txt index 3d167ae9a..c5e5b6c0c 100644 --- a/src/mlt++/CMakeLists.txt +++ b/src/mlt++/CMakeLists.txt @@ -1,6 +1,38 @@ +set(MLTPP_PUPLIC_HEADERS + Mlt.h + MltAnimation.h + MltAudio.h + MltChain.h + MltConfig.h + MltConsumer.h + MltDeque.h + MltEvent.h + MltFactory.h + MltField.h + MltFilter.h + MltFilteredConsumer.h + MltFilteredProducer.h + MltFrame.h + MltImage.h + MltLink.h + MltMultitrack.h + MltParser.h + MltPlaylist.h + MltProducer.h + MltProfile.h + MltProperties.h + MltPushConsumer.h + MltRepository.h + MltService.h + MltTokeniser.h + MltTractor.h + MltTransition.h +) + add_library(mlt++ SHARED MltAnimation.cpp MltAudio.cpp + MltChain.cpp MltConsumer.cpp MltDeque.cpp MltEvent.cpp @@ -10,7 +42,8 @@ add_library(mlt++ SHARED MltFilteredConsumer.cpp MltFilteredProducer.cpp MltFrame.cpp - MltGeometry.cpp + MltImage.cpp + MltLink.cpp MltMultitrack.cpp MltParser.cpp MltPlaylist.cpp @@ -25,62 +58,51 @@ add_library(mlt++ SHARED MltTransition.cpp ) -target_link_libraries(mlt++ mlt) +add_library(Mlt${MLT_VERSION_MAJOR}::mlt++ ALIAS mlt++) + +target_compile_options(mlt++ PRIVATE ${MLT_COMPILE_OPTIONS}) + +target_link_libraries(mlt++ PUBLIC mlt) target_include_directories(mlt++ PUBLIC $ - $ + $ ) -set(MLTPP_SOVERSION "3") - -set_target_properties(mlt++ PROPERTIES SOVERSION ${MLTPP_SOVERSION} VERSION ${MLT_VERSION}) +set_target_properties(mlt++ PROPERTIES + VERSION ${MLT_VERSION} + SOVERSION ${MLT_VERSION_MAJOR} + OUTPUT_NAME mlt++-${MLT_VERSION_MAJOR} + PUBLIC_HEADER "${MLTPP_PUPLIC_HEADERS}" +) if(WIN32) - set_target_properties(mlt++ PROPERTIES OUTPUT_NAME "mlt++-${MLTPP_SOVERSION}") + if(MINGW) + install(FILES "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libmlt++-${MLT_VERSION_MAJOR}.dll" + DESTINATION ${CMAKE_INSTALL_LIBDIR} + RENAME libmlt++.dll + ) + target_link_options(mlt++ PRIVATE -Wl,--output-def,libmlt++.def) + install(FILES "${CMAKE_BINARY_DIR}/libmlt++.def" DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() target_compile_definitions(mlt++ PUBLIC MLTPP_EXPORTS) endif() -set(MLTPP_PUPLIC_HEADERS - Mlt.h - MltAnimation.h - MltAudio.h - MltConfig.h - MltConsumer.h - MltDeque.h - MltEvent.h - MltFactory.h - MltField.h - MltFilter.h - MltFilteredConsumer.h - MltFilteredProducer.h - MltFrame.h - MltGeometry.h - MltMultitrack.h - MltParser.h - MltPlaylist.h - MltProducer.h - MltProfile.h - MltProperties.h - MltPushConsumer.h - MltRepository.h - MltService.h - MltTokeniser.h - MltTractor.h - MltTransition.h -) - -set_target_properties(mlt++ PROPERTIES PUBLIC_HEADER "${MLTPP_PUPLIC_HEADERS}") +if(NOT (WIN32 OR APPLE)) + target_link_options(mlt++ PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/mlt++.vers) + set_target_properties(mlt++ PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/mlt++.vers) +endif() install(TARGETS mlt++ + EXPORT MltTargets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mlt++ + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mlt-${MLT_VERSION_MAJOR}/mlt++ ) -configure_file(mlt++.pc.in mlt++.pc @ONLY) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mlt++.pc +configure_file(mlt++.pc.in mlt++-${MLT_VERSION_MAJOR}.pc @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mlt++-${MLT_VERSION_MAJOR}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT Development ) diff --git a/src/mlt++/Makefile b/src/mlt++/Makefile index 2592da5f6..29adbbded 100644 --- a/src/mlt++/Makefile +++ b/src/mlt++/Makefile @@ -28,6 +28,7 @@ endif OBJS = MltAudio.o \ MltAnimation.o \ + MltChain.o \ MltConsumer.o \ MltDeque.o \ MltEvent.o \ @@ -37,7 +38,8 @@ OBJS = MltAudio.o \ MltFilteredConsumer.o \ MltFilteredProducer.o \ MltFrame.o \ - MltGeometry.o \ + MltImage.o \ + MltLink.o \ MltMultitrack.o \ MltParser.o \ MltPlaylist.o \ diff --git a/src/mlt++/Mlt.h b/src/mlt++/Mlt.h index 89ed7fe6e..9253b408a 100644 --- a/src/mlt++/Mlt.h +++ b/src/mlt++/Mlt.h @@ -23,6 +23,7 @@ #include "MltAudio.h" #include "MltAnimation.h" +#include "MltChain.h" #include "MltConsumer.h" #include "MltDeque.h" #include "MltEvent.h" @@ -31,7 +32,7 @@ #include "MltFilter.h" #include "MltFilteredConsumer.h" #include "MltFrame.h" -#include "MltGeometry.h" +#include "MltImage.h" #include "MltMultitrack.h" #include "MltParser.h" #include "MltPlaylist.h" diff --git a/src/mlt++/MltAnimation.cpp b/src/mlt++/MltAnimation.cpp index d11e97e67..099f6d5a6 100644 --- a/src/mlt++/MltAnimation.cpp +++ b/src/mlt++/MltAnimation.cpp @@ -174,6 +174,11 @@ int Animation::key_set_frame(int index, int frame) return mlt_animation_key_set_frame(instance, index, frame); } +void Animation::shift_frames( int shift ) +{ + return mlt_animation_shift_frames(instance, shift); +} + void Animation::set_length( int length ) { return mlt_animation_set_length( instance, length ); diff --git a/src/mlt++/MltAnimation.h b/src/mlt++/MltAnimation.h index e989ceaba..02d173d54 100644 --- a/src/mlt++/MltAnimation.h +++ b/src/mlt++/MltAnimation.h @@ -52,7 +52,7 @@ namespace Mlt mlt_keyframe_type key_get_type( int index ); int key_set_type( int index, mlt_keyframe_type type ); int key_set_frame( int index, int frame ); - + void shift_frames( int shift ); void set_length( int length ); int remove( int position ); void interpolate(); diff --git a/src/mlt++/MltChain.cpp b/src/mlt++/MltChain.cpp new file mode 100644 index 000000000..d1df6147f --- /dev/null +++ b/src/mlt++/MltChain.cpp @@ -0,0 +1,123 @@ +/** + * MltChain.cpp - Chain wrapper + * Copyright (C) 2020 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 "MltChain.h" + +using namespace Mlt; + +Chain::Chain( ) : + instance( nullptr ) +{ +} + +Chain::Chain( Profile& profile, const char *id, const char *service ) : + instance( mlt_chain_init( profile.get_profile() ) ) +{ + Mlt::Producer source( profile, id, service ); + mlt_chain_set_source( instance, source.get_producer() ); +} + +Chain::Chain( Profile& profile ) : + instance( mlt_chain_init( profile.get_profile() ) ) +{ +} + +Chain::Chain( mlt_chain chain ) : + instance( chain ) +{ + inc_ref( ); +} + +Chain::Chain( Chain& chain ) : + Mlt::Producer( chain ), + instance( chain.get_chain( ) ) +{ + inc_ref( ); +} + +Chain::Chain( Chain* chain ) : + Mlt::Producer( chain ), + instance( chain != NULL ? chain->get_chain( ) : NULL ) +{ + if ( is_valid( ) ) + inc_ref( ); +} + +Chain::Chain( Service& chain ) : + instance( NULL ) +{ + if ( chain.type( ) == mlt_service_chain_type ) + { + instance = ( mlt_chain )chain.get_service( ); + inc_ref( ); + } +} + +Chain::~Chain( ) +{ + mlt_chain_close( instance ); + instance = nullptr; +} + +mlt_chain Chain::get_chain( ) +{ + return instance; +} + +mlt_producer Chain::get_producer( ) +{ + return MLT_CHAIN_PRODUCER( instance ); +} + +void Chain::set_source( Mlt::Producer& source ) +{ + mlt_chain_set_source( instance, source.get_producer() ); +} + +Mlt::Producer Chain::get_source( ) +{ + return Mlt::Producer( mlt_chain_get_source(instance) ); +} + +int Chain::attach( Mlt::Link& link ) +{ + return mlt_chain_attach( instance, link.get_link() ); +} + +int Chain::detach( Mlt::Link& link ) +{ + return mlt_chain_detach( instance, link.get_link() ); +} + +int Chain::link_count() const +{ + return mlt_chain_link_count( instance ); +} + +bool Chain::move_link( int from, int to ) +{ + return (bool)mlt_chain_move_link( instance, from, to ); +} + +Mlt::Link* Chain::link( int index ) +{ + mlt_link result = mlt_chain_link( instance, index ); + return result == NULL ? NULL : new Link( result ); + +} diff --git a/src/mlt++/MltChain.h b/src/mlt++/MltChain.h new file mode 100644 index 000000000..acd756824 --- /dev/null +++ b/src/mlt++/MltChain.h @@ -0,0 +1,59 @@ +/** + * MltChain.h - Chain wrapper + * Copyright (C) 2020 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 MLTPP_CHAIN_H +#define MLTPP_CHAIN_H + +#include "MltConfig.h" + +#include + +#include "MltLink.h" +#include "MltProducer.h" +#include "MltProfile.h" + +namespace Mlt +{ + class MLTPP_DECLSPEC Chain : public Producer + { + private: + mlt_chain instance; + public: + Chain( ); + Chain( Profile& profile, const char *id, const char *service = NULL ); + Chain( Mlt::Profile& profile ); + Chain( mlt_chain chain ); + Chain( Chain& chain ); + Chain( Chain* chain ); + Chain( Service& chain ); + virtual ~Chain( ); + virtual mlt_chain get_chain( ); + mlt_producer get_producer( ); + void set_source( Mlt::Producer& source ); + Mlt::Producer get_source( ); + int attach( Mlt::Link& link ); + int detach( Mlt::Link& link ); + int link_count() const; + bool move_link( int from, int to ); + Mlt::Link* link( int index ); + }; +} + +#endif + diff --git a/src/mlt++/MltConsumer.cpp b/src/mlt++/MltConsumer.cpp index b70e24724..891ed502e 100644 --- a/src/mlt++/MltConsumer.cpp +++ b/src/mlt++/MltConsumer.cpp @@ -68,7 +68,7 @@ Consumer::Consumer( mlt_profile profile, const char *id, const char *arg ) : Consumer::Consumer( Service &consumer ) : instance( NULL ) { - if ( consumer.type( ) == consumer_type ) + if ( consumer.type( ) == mlt_service_consumer_type ) { instance = ( mlt_consumer )consumer.get_service( ); inc_ref( ); diff --git a/src/mlt++/MltEvent.cpp b/src/mlt++/MltEvent.cpp index e9f81b43d..c395f64c3 100644 --- a/src/mlt++/MltEvent.cpp +++ b/src/mlt++/MltEvent.cpp @@ -1,7 +1,6 @@ /** * MltEvent.cpp - MLT Wrapper - * Copyright (C) 2004-2015 Meltytech, LLC - * Author: Charles Yates + * Copyright (C) 2004-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 @@ -19,6 +18,7 @@ */ #include "MltEvent.h" +#include "MltFrame.h" using namespace Mlt; @@ -59,3 +59,49 @@ void Event::unblock( ) mlt_event_unblock( get_event( ) ); } + +EventData::EventData(mlt_event_data data) + : instance(data) +{ +} + +EventData::EventData(EventData& data) + : instance(data.get_event_data()) +{ +} + +EventData::EventData(const EventData& data) + : instance(data.get_event_data()) +{ +} + +EventData& EventData::operator=(const EventData& data) +{ + instance = data.get_event_data(); + return *this; +} + +mlt_event_data EventData::get_event_data() const +{ + return instance; +} + +int EventData::to_int() const +{ + return mlt_event_data_to_int(instance); +} + +const char* EventData::to_string() const +{ + return mlt_event_data_to_string(instance); +} + +Frame EventData::to_frame() const +{ + return Frame(mlt_event_data_to_frame(instance)); +} + +void* EventData::to_object() const +{ + return mlt_event_data_to_object(instance); +} diff --git a/src/mlt++/MltEvent.h b/src/mlt++/MltEvent.h index e79dc1f19..6fd543658 100644 --- a/src/mlt++/MltEvent.h +++ b/src/mlt++/MltEvent.h @@ -1,7 +1,6 @@ /** * MltEvent.h - MLT Wrapper - * Copyright (C) 2004-2015 Meltytech, LLC - * Author: Charles Yates + * Copyright (C) 2004-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 @@ -27,7 +26,9 @@ namespace Mlt { - class MLTPP_DECLSPEC Event + class Frame; + + class MLTPP_DECLSPEC Event { private: mlt_event instance; @@ -40,6 +41,23 @@ namespace Mlt void block( ); void unblock( ); }; + + class MLTPP_DECLSPEC EventData + { + private: + mlt_event_data instance; + public: + EventData(mlt_event_data); + EventData(EventData&); + EventData(const EventData&); + EventData& operator=(const EventData&); + ~EventData() {}; + mlt_event_data get_event_data() const; + int to_int() const; + const char* to_string() const; + Frame to_frame() const; + void* to_object() const; + }; } #endif diff --git a/src/mlt++/MltFilter.cpp b/src/mlt++/MltFilter.cpp index 3fb8c2f29..45aad9e80 100644 --- a/src/mlt++/MltFilter.cpp +++ b/src/mlt++/MltFilter.cpp @@ -61,7 +61,7 @@ Filter::Filter( mlt_profile profile, const char *id, const char *arg ) : Filter::Filter( Service &filter ) : instance( NULL ) { - if ( filter.type( ) == filter_type ) + if ( filter.type( ) == mlt_service_filter_type ) { instance = ( mlt_filter )filter.get_service( ); inc_ref( ); diff --git a/src/mlt++/MltGeometry.cpp b/src/mlt++/MltGeometry.cpp deleted file mode 100644 index 254e1f172..000000000 --- a/src/mlt++/MltGeometry.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/** - * MltGeometry.cpp - MLT Wrapper - * Copyright (C) 2004-2015 Meltytech, LLC - * Author: Charles Yates - * - * 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 "MltGeometry.h" -using namespace Mlt; - -Geometry::Geometry( char *data, int length, int nw, int nh ) -{ - geometry = mlt_geometry_init( ); - parse( data, length, nw, nh ); -} - -Geometry::~Geometry( ) -{ - mlt_geometry_close( geometry ); -} - -int Geometry::parse( char *data, int length, int nw, int nh ) -{ - return mlt_geometry_parse( geometry, data, length, nw, nh ); -} - -// Fetch a geometry item for an absolute position -int Geometry::fetch( GeometryItem &item, float position ) -{ - return mlt_geometry_fetch( geometry, item.get_item( ), position ); -} - -int Geometry::fetch( GeometryItem *item, float position ) -{ - return mlt_geometry_fetch( geometry, item->get_item( ), position ); -} - -// Specify a geometry item at an absolute position -int Geometry::insert( GeometryItem &item ) -{ - return mlt_geometry_insert( geometry, item.get_item( ) ); -} - -int Geometry::insert( GeometryItem *item ) -{ - return mlt_geometry_insert( geometry, item->get_item( ) ); -} - -// Remove the key at the specified position -int Geometry::remove( int position ) -{ - return mlt_geometry_remove( geometry, position ); -} - -void Geometry::interpolate( ) -{ - mlt_geometry_interpolate( geometry ); -} - -// Get the key at the position or the next following -int Geometry::next_key( GeometryItem &item, int position ) -{ - return mlt_geometry_next_key( geometry, item.get_item( ), position ); -} - -int Geometry::next_key( GeometryItem *item, int position ) -{ - return mlt_geometry_next_key( geometry, item->get_item( ), position ); -} - -int Geometry::prev_key( GeometryItem &item, int position ) -{ - return mlt_geometry_prev_key( geometry, item.get_item( ), position ); -} - -int Geometry::prev_key( GeometryItem *item, int position ) -{ - return mlt_geometry_prev_key( geometry, item->get_item( ), position ); -} - -// Serialise the current geometry -char *Geometry::serialise( int in, int out ) -{ - return mlt_geometry_serialise_cut( geometry, in, out ); -} - -char *Geometry::serialise( ) -{ - return mlt_geometry_serialise( geometry ); -} - diff --git a/src/mlt++/MltGeometry.h b/src/mlt++/MltGeometry.h deleted file mode 100644 index 509061363..000000000 --- a/src/mlt++/MltGeometry.h +++ /dev/null @@ -1,81 +0,0 @@ -/** - * MltGeometry.h - MLT Wrapper - * Copyright (C) 2004-2015 Meltytech, LLC - * Author: Charles Yates - * - * 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 MLTPP_GEOMETRY_H -#define MLTPP_GEOMETRY_H - -#include "MltConfig.h" - -#include - -namespace Mlt -{ - // Just for consistent naming purposes - class MLTPP_DECLSPEC GeometryItem - { - private: - struct mlt_geometry_item_s item; - public: - mlt_geometry_item get_item( ) { return &item; } - bool key( ) { return item.key != 0; } - int frame( ) { return item.frame; } - void frame( int value ) { item.frame = value; } - float x( ) { return item.x; } - void x( float value ) { item.f[0] = 1; item.x = value; } - float y( ) { return item.y; } - void y( float value ) { item.f[1] = 1; item.y = value; } - float w( ) { return item.w; } - void w( float value ) { item.f[2] = 1; item.w = value; } - float h( ) { return item.h; } - void h( float value ) { item.f[3] = 1; item.h = value; } - float mix( ) { return item.mix; } - void mix( float value ) { item.f[4] = 1; item.mix = value; } - }; - - class MLTPP_DECLSPEC Geometry - { - private: - mlt_geometry geometry; - public: - Geometry( char *data = NULL, int length = 0, int nw = -1, int nh = -1 ); - ~Geometry( ); - int parse( char *data, int length, int nw = -1, int nh = -1 ); - // Fetch a geometry item for an absolute position - int fetch( GeometryItem &item, float position ); - int fetch( GeometryItem *item, float position ); - // Specify a geometry item at an absolute position - int insert( GeometryItem &item ); - int insert( GeometryItem *item ); - // Remove the key at the specified position - int remove( int position ); - void interpolate( ); - // Get the key at the position or the next following - int next_key( GeometryItem &item, int position ); - int next_key( GeometryItem *item, int position ); - int prev_key( GeometryItem &item, int position ); - int prev_key( GeometryItem *item, int position ); - // Serialise the current geometry - char *serialise( int in, int out ); - char *serialise( ); - }; -} - -#endif - diff --git a/src/mlt++/MltImage.cpp b/src/mlt++/MltImage.cpp new file mode 100644 index 000000000..7d05ea5c3 --- /dev/null +++ b/src/mlt++/MltImage.cpp @@ -0,0 +1,93 @@ +/** + * MltImage.cpp - MLT Wrapper + * Copyright (C) 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 "MltImage.h" + +using namespace Mlt; + +Image::Image( ) +{ + instance = mlt_image_new(); +} + +Image::Image( mlt_image image ) + : instance( image ) +{ +} + +Image::Image( int width, int height, mlt_image_format format ) +{ + instance = mlt_image_new(); + alloc( width, height, format ); +} + +Image::~Image( ) +{ + mlt_image_close( instance ); +} + +mlt_image_format Image::format() +{ + return instance->format; +} + +int Image::width() +{ + return instance->width; +} + +int Image::height() +{ + return instance->height; +} + +void Image::set_colorspace( int colorspace ) +{ + instance->colorspace = colorspace; +} + +int Image::colorspace() +{ + return instance->colorspace; +} + +void Image::alloc( int width, int height, mlt_image_format format, bool alpha ) +{ + instance->width = width; + instance->height = height; + instance->format = format; + mlt_image_alloc_data( instance ); + if ( alpha ) + mlt_image_alloc_alpha( instance ); +} + +void Image::init_alpha() +{ + mlt_image_alloc_alpha( instance ); +} + +uint8_t* Image::plane( int plane ) +{ + return instance->planes[plane]; +} + +int Image::stride( int plane ) +{ + return instance->strides[plane]; +} diff --git a/src/mlt++/MltImage.h b/src/mlt++/MltImage.h new file mode 100644 index 000000000..c148d0030 --- /dev/null +++ b/src/mlt++/MltImage.h @@ -0,0 +1,50 @@ +/** + * MltImage.h - MLT Wrapper + * Copyright (C) 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 + */ + +#ifndef MLTPP_IMAGE_H +#define MLTPP_IMAGE_H + +#include "MltConfig.h" + +#include + +namespace Mlt +{ + class MLTPP_DECLSPEC Image + { + private: + mlt_image instance; + public: + Image(); + Image( mlt_image image ); + Image( int width, int height, mlt_image_format format ); + virtual ~Image( ); + mlt_image_format format(); + int width(); + int height(); + void set_colorspace( int colorspace ); + int colorspace(); + void alloc( int width, int height, mlt_image_format format, bool alpha = false ); + void init_alpha(); + uint8_t* plane( int plane ); + int stride( int plane ); + }; +} + +#endif diff --git a/src/mlt++/MltLink.cpp b/src/mlt++/MltLink.cpp new file mode 100644 index 000000000..08b204f77 --- /dev/null +++ b/src/mlt++/MltLink.cpp @@ -0,0 +1,82 @@ +/** + * MltLink.cpp - MLT Wrapper + * Copyright (C) 2020 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 "MltLink.h" +#include "MltProfile.h" + +#include +#include + +using namespace Mlt; + +Link::Link( ) : + instance( nullptr ) +{ +} + +Link::Link( mlt_link link ) + : instance( link ) +{ + inc_ref( ); +} + +Link::Link( const char *id, const char *arg ) : + instance( NULL ) +{ + if ( arg != NULL ) + { + instance = mlt_factory_link( id, arg ); + } + else + { + if ( strchr( id, ':' ) ) + { + char *temp = strdup( id ); + char *arg = strchr( temp, ':' ) + 1; + *( arg - 1 ) = '\0'; + instance = mlt_factory_link( temp, arg ); + free( temp ); + } + else + { + instance = mlt_factory_link( id, NULL ); + } + } +} + +Link::~Link( ) +{ + mlt_link_close( instance ); +} + +mlt_link Link::get_link( ) +{ + return instance; +} + +mlt_producer Link::get_producer( ) +{ + return MLT_LINK_PRODUCER( instance ); +} + +int Link::connect_next( Mlt::Producer& next, Mlt::Profile& default_profile ) +{ + return mlt_link_connect_next( instance, next.get_producer(), default_profile.get_profile() ); +} + diff --git a/src/modules/core/transition_region.h b/src/mlt++/MltLink.h similarity index 55% rename from src/modules/core/transition_region.h rename to src/mlt++/MltLink.h index f217d62f9..a9825a3cd 100644 --- a/src/modules/core/transition_region.h +++ b/src/mlt++/MltLink.h @@ -1,6 +1,6 @@ -/* - * transition_region.h -- region transition - * Copyright (C) 2003-2014 Meltytech, LLC +/** + * MltLink.h - MLT Wrapper + * Copyright (C) 2020 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,11 +17,33 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _TRANSITION_REGION_H_ -#define _TRANSITION_REGION_H_ +#ifndef MLTPP_LINK_H +#define MLTPP_LINK_H -#include +#include "MltConfig.h" +#include "MltProducer.h" +#include "MltProducer.h" -extern mlt_transition transition_region_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +#include + +namespace Mlt +{ + class Producer; + class Profile; + + class MLTPP_DECLSPEC Link : public Producer + { + private: + mlt_link instance; + public: + Link( ); + Link( mlt_link link ); + Link( const char* id, const char* service = NULL ); + virtual ~Link( ); + virtual mlt_link get_link( ); + mlt_producer get_producer( ); + int connect_next( Mlt::Producer& next, Mlt::Profile& default_profile ); + }; +} #endif diff --git a/src/mlt++/MltMultitrack.cpp b/src/mlt++/MltMultitrack.cpp index f76a42ff3..68951e7ad 100644 --- a/src/mlt++/MltMultitrack.cpp +++ b/src/mlt++/MltMultitrack.cpp @@ -31,7 +31,7 @@ Multitrack::Multitrack( mlt_multitrack multitrack ) : Multitrack::Multitrack( Service &multitrack ) : instance( NULL ) { - if ( multitrack.type( ) == multitrack_type ) + if ( multitrack.type( ) == mlt_service_multitrack_type ) { instance = ( mlt_multitrack )multitrack.get_service( ); inc_ref( ); diff --git a/src/mlt++/MltParser.cpp b/src/mlt++/MltParser.cpp index 34006c46b..d8f7f869f 100644 --- a/src/mlt++/MltParser.cpp +++ b/src/mlt++/MltParser.cpp @@ -147,6 +147,38 @@ static int on_end_transition_cb( mlt_parser self, mlt_transition object ) return parser->on_end_transition( &transition ); } +static int on_start_chain_cb( mlt_parser self, mlt_chain object ) +{ + mlt_properties properties = mlt_parser_properties( self ); + Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); + Chain chain( object ); + return parser->on_start_chain( &chain ); +} + +static int on_end_chain_cb( mlt_parser self, mlt_chain object ) +{ + mlt_properties properties = mlt_parser_properties( self ); + Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); + Chain chain( object ); + return parser->on_end_chain( &chain ); +} + +static int on_start_link_cb( mlt_parser self, mlt_link object ) +{ + mlt_properties properties = mlt_parser_properties( self ); + Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); + Link link( object ); + return parser->on_start_link( &link ); +} + +static int on_end_link_cb( mlt_parser self, mlt_link object ) +{ + mlt_properties properties = mlt_parser_properties( self ); + Parser *parser = ( Parser * )mlt_properties_get_data( properties, "_parser_object", NULL ); + Link link( object ); + return parser->on_end_link( &link ); +} + Parser::Parser( ) : Properties( false ) { @@ -168,6 +200,10 @@ Parser::Parser( ) : parser->on_end_filter = on_end_filter_cb; parser->on_start_transition = on_start_transition_cb; parser->on_end_transition = on_end_transition_cb; + parser->on_start_chain = on_start_chain_cb; + parser->on_end_chain = on_end_chain_cb; + parser->on_start_link = on_start_link_cb; + parser->on_end_link = on_end_link_cb; } Parser::~Parser( ) @@ -281,4 +317,26 @@ int Parser::on_end_transition( Transition *object ) return 0; } +int Parser::on_start_chain( Chain *object ) +{ + object->debug( "on_start_chain" ); + return 0; +} +int Parser::on_end_chain( Chain *object ) +{ + object->debug( "on_end_chain" ); + return 0; +} + +int Parser::on_start_link( Link *object ) +{ + object->debug( "on_start_link" ); + return 0; +} + +int Parser::on_end_link( Link *object ) +{ + object->debug( "on_end_link" ); + return 0; +} diff --git a/src/mlt++/MltParser.h b/src/mlt++/MltParser.h index 1cfe092c7..6213d5f90 100644 --- a/src/mlt++/MltParser.h +++ b/src/mlt++/MltParser.h @@ -62,6 +62,10 @@ namespace Mlt virtual int on_end_filter( Filter *object ); virtual int on_start_transition( Transition *object ); virtual int on_end_transition( Transition *object ); + virtual int on_start_chain( Chain *object ); + virtual int on_end_chain( Chain *object ); + virtual int on_start_link( Link *object ); + virtual int on_end_link( Link *object ); }; } diff --git a/src/mlt++/MltPlaylist.cpp b/src/mlt++/MltPlaylist.cpp index d0735176d..6b0698e29 100644 --- a/src/mlt++/MltPlaylist.cpp +++ b/src/mlt++/MltPlaylist.cpp @@ -95,7 +95,7 @@ Playlist::Playlist( Profile& profile ) : Playlist::Playlist( Service &producer ) : instance( NULL ) { - if ( producer.type( ) == playlist_type ) + if ( producer.type( ) == mlt_service_playlist_type ) { instance = ( mlt_playlist )producer.get_service( ); inc_ref( ); @@ -335,9 +335,3 @@ int Playlist::remove_region( int position, int length ) { return mlt_playlist_remove_region( get_playlist( ), position, length ); } - -int Playlist::move_region( int position, int length, int new_position ) -{ - return mlt_playlist_move_region( get_playlist( ), position, length, new_position ); -} - diff --git a/src/mlt++/MltPlaylist.h b/src/mlt++/MltPlaylist.h index 738ad3c37..b7b3c309f 100644 --- a/src/mlt++/MltPlaylist.h +++ b/src/mlt++/MltPlaylist.h @@ -107,7 +107,6 @@ namespace Mlt int clip_length( int clip ); int blanks_from( int clip, int bounded = 0 ); int remove_region( int position, int length ); - int move_region( int position, int length, int new_position ); }; } diff --git a/src/mlt++/MltProducer.cpp b/src/mlt++/MltProducer.cpp index b196f6dc6..00f79b834 100644 --- a/src/mlt++/MltProducer.cpp +++ b/src/mlt++/MltProducer.cpp @@ -50,8 +50,9 @@ Producer::Producer( Service &producer ) : parent_( NULL ) { mlt_service_type type = producer.type( ); - if ( type == producer_type || type == playlist_type || - type == tractor_type || type == multitrack_type ) + if ( type == mlt_service_producer_type || type == mlt_service_playlist_type || + type == mlt_service_tractor_type || type == mlt_service_multitrack_type || + type == mlt_service_chain_type || type == mlt_service_link_type ) { instance = ( mlt_producer )producer.get_service( ); inc_ref( ); diff --git a/src/mlt++/MltProperties.cpp b/src/mlt++/MltProperties.cpp index c377f900d..5114baeeb 100644 --- a/src/mlt++/MltProperties.cpp +++ b/src/mlt++/MltProperties.cpp @@ -1,6 +1,6 @@ /** * MltProperties.cpp - MLT Wrapper - * Copyright (C) 2004-2020 Meltytech, LLC + * Copyright (C) 2004-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 @@ -120,7 +120,7 @@ void Properties::unblock( void *object ) int Properties::fire_event( const char *event ) { - return mlt_events_fire( get_properties( ), event, NULL ); + return mlt_events_fire( get_properties( ), event, mlt_event_data_none() ); } bool Properties::is_valid( ) @@ -271,24 +271,12 @@ int Properties::save( const char *file ) return mlt_properties_save( get_properties( ), file ); } -#if defined( __APPLE__ ) && GCC_VERSION < 40000 - -Event *Properties::listen( const char *id, void *object, void (*listener)( ... ) ) -{ - mlt_event event = mlt_events_listen( get_properties( ), object, id, ( mlt_listener )listener ); - return new Event( event ); -} - -#else - Event *Properties::listen( const char *id, void *object, mlt_listener listener ) { mlt_event event = mlt_events_listen( get_properties( ), object, id, listener ); return new Event( event ); } -#endif - Event *Properties::setup_wait_for( const char *id ) { return new Event( mlt_events_setup_wait_for( get_properties( ), id ) ); diff --git a/src/mlt++/MltProperties.h b/src/mlt++/MltProperties.h index 626b553f6..e0a2341fc 100644 --- a/src/mlt++/MltProperties.h +++ b/src/mlt++/MltProperties.h @@ -1,6 +1,6 @@ /** * MltProperties.h - MLT Wrapper - * Copyright (C) 2004-2020 Meltytech, LLC + * Copyright (C) 2004-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 @@ -85,11 +85,7 @@ namespace Mlt void debug( const char *title = "Object", FILE *output = stderr ); void load( const char *file ); int save( const char *file ); - #if defined( __APPLE__ ) && GCC_VERSION < 40000 - Event *listen( const char *id, void *object, void (*)( ... ) ); - #else Event *listen( const char *id, void *object, mlt_listener ); - #endif static void delete_event( Event * ); Event *setup_wait_for( const char *id ); void wait_for( Event *, bool destroy = true ); diff --git a/src/mlt++/MltRepository.cpp b/src/mlt++/MltRepository.cpp index 264f9453b..ecfe931ef 100644 --- a/src/mlt++/MltRepository.cpp +++ b/src/mlt++/MltRepository.cpp @@ -58,6 +58,11 @@ Properties *Repository::filters( ) const return new Properties( mlt_repository_filters( instance ) ); } +Properties *Repository::links( ) const +{ + return new Properties( mlt_repository_links( instance ) ); +} + Properties *Repository::producers( ) const { return new Properties( mlt_repository_producers( instance ) ); diff --git a/src/mlt++/MltRepository.h b/src/mlt++/MltRepository.h index 52a0ab76f..f2a9ffb80 100644 --- a/src/mlt++/MltRepository.h +++ b/src/mlt++/MltRepository.h @@ -47,6 +47,7 @@ namespace Mlt void *create( Profile& profile, mlt_service_type type, const char *service, void *arg ); Properties *consumers( ) const; Properties *filters( ) const; + Properties *links( ) const; Properties *producers( ) const; Properties *transitions( ) const; void register_metadata( mlt_service_type type, const char *service, mlt_metadata_callback, void *callback_data ); diff --git a/src/mlt++/MltTractor.cpp b/src/mlt++/MltTractor.cpp index 3cf7b6c4f..b0e26a6f1 100644 --- a/src/mlt++/MltTractor.cpp +++ b/src/mlt++/MltTractor.cpp @@ -40,7 +40,7 @@ Tractor::Tractor( Profile& profile ) : Tractor::Tractor( Service &tractor ) : instance( NULL ) { - if ( tractor.type( ) == tractor_type ) + if ( tractor.type( ) == mlt_service_tractor_type ) { instance = ( mlt_tractor )tractor.get_service( ); inc_ref( ); @@ -69,7 +69,7 @@ Tractor::Tractor( mlt_profile profile, char *id, char *resource ) : instance( NULL ) { Producer producer( profile, id, resource ); - if ( producer.is_valid( ) && producer.type( ) == tractor_type ) + if ( producer.is_valid( ) && producer.type( ) == mlt_service_tractor_type ) { instance = ( mlt_tractor )producer.get_producer( ); inc_ref( ); diff --git a/src/mlt++/MltTransition.cpp b/src/mlt++/MltTransition.cpp index 29491d4d4..85dccf0f4 100644 --- a/src/mlt++/MltTransition.cpp +++ b/src/mlt++/MltTransition.cpp @@ -62,7 +62,7 @@ Transition::Transition( mlt_profile profile, const char *id, const char *arg ) : Transition::Transition( Service &transition ) : instance( NULL ) { - if ( transition.type( ) == transition_type ) + if ( transition.type( ) == mlt_service_transition_type ) { instance = ( mlt_transition )transition.get_service( ); inc_ref( ); diff --git a/src/mlt++/MltTransition.h b/src/mlt++/MltTransition.h index 92cea2a3a..82c7e0796 100644 --- a/src/mlt++/MltTransition.h +++ b/src/mlt++/MltTransition.h @@ -30,6 +30,8 @@ namespace Mlt class Service; class Profile; class Frame; + class Chain; + class Link; class MLTPP_DECLSPEC Transition : public Service { diff --git a/src/mlt++/configure b/src/mlt++/configure index fc42e4554..fa95b2499 100755 --- a/src/mlt++/configure +++ b/src/mlt++/configure @@ -1,5 +1,4 @@ #!/bin/sh -echo "soversion=3" > config.mak echo "mlt++ -I$includedir -I$includedir/mlt++ -D_REENTRANT -L$libdir -lmlt++" >> ../../packages.dat WARNINGS="-W -Wwrite-strings -Wcast-qual -Wpointer-arith -Wcast-align -Wredundant-decls" diff --git a/src/mlt++/mlt++.pc.in b/src/mlt++/mlt++.pc.in index 3719cd83a..ef7a870b2 100644 --- a/src/mlt++/mlt++.pc.in +++ b/src/mlt++/mlt++.pc.in @@ -7,6 +7,6 @@ datadir=@CMAKE_INSTALL_FULL_DATADIR@ Name: mlt++ Description: C++ API for MLT multimedia framework Version: @MLT_VERSION@ -Requires: mlt-framework -Libs: -L${libdir} -lmlt++ -Cflags: -I${includedir} -I${includedir}/mlt++ +Requires: mlt-framework-@MLT_VERSION_MAJOR@ +Libs: -L${libdir} -lmlt++-@MLT_VERSION_MAJOR@ +Cflags: -I${includedir}/mlt-@MLT_VERSION_MAJOR@/mlt++ diff --git a/src/mlt++/mlt++.vers b/src/mlt++/mlt++.vers index f9997ee37..da4f6f4d2 100644 --- a/src/mlt++/mlt++.vers +++ b/src/mlt++/mlt++.vers @@ -612,3 +612,76 @@ MLTPP_6.22.0 { "Mlt::Audio::set_layout(mlt_channel_layout)"; }; } MLTPP_6.20.0; + +MLTPP_7.0.0 { + global: + extern "C++" { + "typeinfo for Mlt::Audio"; + "typeinfo name for Mlt::Audio"; + "vtable for Mlt::Audio"; + "typeinfo for Mlt::Image"; + "typeinfo name for Mlt::Image"; + "vtable for Mlt::Image"; + "typeinfo for Mlt::Link"; + "typeinfo name for Mlt::Link"; + "vtable for Mlt::Link"; + "typeinfo for Mlt::Chain"; + "typeinfo name for Mlt::Chain"; + "vtable for Mlt::Chain"; + "Mlt::Link::Link()"; + "Mlt::Link::Link(mlt_link_s*)"; + "Mlt::Link::Link(char const*, char const*)"; + "Mlt::Link::~Link()"; + "Mlt::Link::get_link()"; + "Mlt::Link::get_producer()"; + "Mlt::Link::connect_next(Mlt::Producer&, Mlt::Profile&)"; + "Mlt::Chain::Chain()"; + "Mlt::Chain::Chain(Mlt::Profile&, char const*, char const*)"; + "Mlt::Chain::Chain(Mlt::Profile&)"; + "Mlt::Chain::Chain(mlt_chain)"; + "Mlt::Chain::Chain(Mlt::Chain&)"; + "Mlt::Chain::Chain(Mlt::Chain*)"; + "Mlt::Chain::Chain(Mlt::Service&)"; + "Mlt::Chain::~Chain()"; + "Mlt::Chain::get_chain()"; + "Mlt::Chain::get_producer()"; + "Mlt::Chain::set_source(Mlt::Producer&)"; + "Mlt::Chain::get_source()"; + "Mlt::Chain::attach(Mlt::Link&)"; + "Mlt::Chain::detach(Mlt::Link&)"; + "Mlt::Chain::link_count() const"; + "Mlt::Chain::move_link(int, int)"; + "Mlt::Chain::link(int)"; + "Mlt::Repository::links() const"; + "Mlt::Parser::on_start_chain(Mlt::Chain*)"; + "Mlt::Parser::on_end_chain(Mlt::Chain*)"; + "Mlt::Parser::on_start_link(Mlt::Link*)"; + "Mlt::Parser::on_end_link(Mlt::Link*)"; + "Mlt::Animation::shift_frames(int)"; + "Mlt::Image::Image()"; + "Mlt::Image::Image(mlt_image_s*)"; + "Mlt::Image::Image(int, int, mlt_image_format)"; + "Mlt::Image::~Image()"; + "Mlt::Image::format()"; + "Mlt::Image::width()"; + "Mlt::Image::height()"; + "Mlt::Image::set_colorspace(int)"; + "Mlt::Image::colorspace()"; + "Mlt::Image::alloc(int, int, mlt_image_format, bool)"; + "Mlt::Image::init_alpha()"; + "Mlt::Image::plane(int)"; + "Mlt::Image::stride(int)"; + "Mlt::Properties::listen(char const*, void*, void (*)(mlt_properties_s*, void*, mlt_event_data))"; + "typeinfo name for Mlt::EventData"; + "vtable for Mlt::EventData"; + "Mlt::EventData::EventData(mlt_event_data)"; + "Mlt::EventData::EventData(Mlt::EventData&)"; + "Mlt::EventData::EventData(Mlt::EventData const&)"; + "Mlt::EventData::operator=(Mlt::EventData const&)"; + "Mlt::EventData::get_event_data() const"; + "Mlt::EventData::to_int() const"; + "Mlt::EventData::to_string() const"; + "Mlt::EventData::to_frame() const"; + "Mlt::EventData::to_object() const"; + }; +} MLTPP_6.22.0; diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt index 45e57803a..c2e551a37 100644 --- a/src/modules/CMakeLists.txt +++ b/src/modules/CMakeLists.txt @@ -1,6 +1,6 @@ add_subdirectory(core) -if(MOD_AVFORMAT AND TARGET PkgConfig::libavformat AND TARGET PkgConfig::libswscale AND TARGET PkgConfig::libavutil) +if(MOD_AVFORMAT) add_subdirectory(avformat) endif() @@ -8,23 +8,15 @@ if(MOD_DECKLINK) add_subdirectory(decklink) endif() -if(MOD_FEEDS) - add_subdirectory(feeds) -endif() - -if(MOD_FREI0R AND FREI0R_FOUND) +if(MOD_FREI0R) add_subdirectory(frei0r) endif() -if(MOD_GDK AND TARGET PkgConfig::GdkPixbuf) +if(MOD_GDK) add_subdirectory(gdk) endif() -if(MOD_GTK2) - add_subdirectory(gtk2) -endif() - -if(MOD_JACKRACK AND TARGET PkgConfig::jack) +if(MOD_JACKRACK) add_subdirectory(jackrack) endif() @@ -32,15 +24,11 @@ if(MOD_KDENLIVE) add_subdirectory(kdenlive) endif() -if(MOD_LUMAS) - add_subdirectory(lumas) +if(MOD_NDI) + add_subdirectory(ndi) endif() -if(MOD_MOTION_EST AND GPL) - add_subdirectory(motion_est) -endif() - -if(MOD_NORMALIZE AND GPL) +if(MOD_NORMALIZE) add_subdirectory(normalize) endif() @@ -48,27 +36,27 @@ if(MOD_OLDFILM) add_subdirectory(oldfilm) endif() -if(MOD_OPENCV AND OpenCV_tracking_FOUND) +if(MOD_OPENCV) add_subdirectory(opencv) endif() -if(MOD_OPENGL AND TARGET PkgConfig::movit AND TARGET OpenGL::GL) - add_subdirectory(opengl) +if(MOD_MOVIT) + add_subdirectory(movit) endif() if(MOD_PLUS) add_subdirectory(plus) endif() -if(MOD_PLUSGPL AND GPL) +if(MOD_PLUSGPL) add_subdirectory(plusgpl) endif() -if(MOD_QT AND GPL AND Qt5_FOUND) +if(MOD_QT) add_subdirectory(qt) endif() -if(MOD_RESAMPLE AND TARGET PkgConfig::samplerate) +if(MOD_RESAMPLE) add_subdirectory(resample) endif() @@ -76,38 +64,34 @@ if(MOD_RTAUDIO) add_subdirectory(rtaudio) endif() -if(MOD_RUBBERBAND AND GPL AND TARGET PkgConfig::rubberband) +if(MOD_RUBBERBAND) add_subdirectory(rubberband) endif() -if(MOD_SDL1 AND TARGET PkgConfig::sdl) +if(MOD_SDL1) add_subdirectory(sdl) endif() -if(MOD_SDL2 AND TARGET sdl2) +if(MOD_SDL2) add_subdirectory(sdl2) endif() -if(MOD_SOX AND TARGET PkgConfig::sox) +if(MOD_SOX) add_subdirectory(sox) endif() -if(MOD_VIDSTAB AND GPL AND TARGET PkgConfig::vidstab) +if(MOD_VIDSTAB) add_subdirectory(vid.stab) endif() -if(MOD_VMFX) - add_subdirectory(vmfx) -endif() - -if(MOD_VORBIS AND TARGET PkgConfig::vorbis AND TARGET PkgConfig::vorbisfile) +if(MOD_VORBIS) add_subdirectory(vorbis) endif() -if(MOD_XINE AND GPL) +if(MOD_XINE) add_subdirectory(xine) endif() -if(MOD_XML AND TARGET PkgConfig::xml) +if(MOD_XML) add_subdirectory(xml) endif() diff --git a/src/modules/avformat/CMakeLists.txt b/src/modules/avformat/CMakeLists.txt index 32a5898f4..146702e46 100644 --- a/src/modules/avformat/CMakeLists.txt +++ b/src/modules/avformat/CMakeLists.txt @@ -6,6 +6,8 @@ add_library(mltavformat MODULE filter_swscale.c ) +target_compile_options(mltavformat PRIVATE ${MLT_COMPILE_OPTIONS}) + target_link_libraries(mltavformat PRIVATE mlt m @@ -44,10 +46,13 @@ if(TARGET PkgConfig::libswresample) target_compile_definitions(mltavformat PRIVATE SWRESAMPLE) endif() -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltavformat PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +if(CPU_MMX) + target_compile_definitions(mltavformat PRIVATE USE_MMX) +endif() + +set_target_properties(mltavformat PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(TARGETS mltavformat LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +install(TARGETS mltavformat LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES consumer_avformat.yml @@ -55,5 +60,5 @@ install(FILES resolution_scale.yml blacklist.txt yuv_only.txt - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/avformat + DESTINATION ${MLT_INSTALL_DATA_DIR}/avformat ) diff --git a/src/modules/avformat/consumer_avformat.c b/src/modules/avformat/consumer_avformat.c index 125e0a59d..efd29b29e 100644 --- a/src/modules/avformat/consumer_avformat.c +++ b/src/modules/avformat/consumer_avformat.c @@ -213,7 +213,7 @@ static int init_vaapi(mlt_properties properties, AVCodecContext *codec_context) #endif // Forward references. -static void property_changed( mlt_properties owner, mlt_consumer self, char *name ); +static void property_changed(mlt_properties owner, mlt_consumer self, mlt_event_data ); static int consumer_start( mlt_consumer consumer ); static int consumer_stop( mlt_consumer consumer ); static int consumer_is_stopped( mlt_consumer consumer ); @@ -267,7 +267,7 @@ mlt_consumer consumer_avformat_init( mlt_profile profile, char *arg ) consumer->stop = consumer_stop; consumer->is_stopped = consumer_is_stopped; - mlt_events_register( properties, "consumer-fatal-error", NULL ); + mlt_events_register( properties, "consumer-fatal-error" ); mlt_event event = mlt_events_listen( properties, consumer, "property-changed", ( mlt_listener )property_changed ); mlt_properties_set_data( properties, "property-changed event", event, 0, NULL, NULL ); } @@ -352,11 +352,12 @@ static void color_primaries_from_colorspace( mlt_properties properties ) } } -static void property_changed( mlt_properties owner, mlt_consumer self, char *name ) +static void property_changed( mlt_properties owner, mlt_consumer self, mlt_event_data event_data ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); + const char *name = mlt_event_data_to_string(event_data); - if ( !strcmp( name, "s" ) ) + if ( name && !strcmp( name, "s" ) ) { // Obtain the size property char *size = mlt_properties_get( properties, "s" ); @@ -581,9 +582,9 @@ static enum AVPixelFormat pick_pix_fmt( mlt_image_format img_fmt ) { switch ( img_fmt ) { - case mlt_image_rgb24: + case mlt_image_rgb: return AV_PIX_FMT_RGB24; - case mlt_image_rgb24a: + case mlt_image_rgba: return AV_PIX_FMT_RGBA; case mlt_image_yuv420p: return AV_PIX_FMT_YUV420P; @@ -1189,19 +1190,19 @@ static inline long time_difference( struct timeval *time1 ) return time2.tv_sec * 1000000 + time2.tv_usec - time1->tv_sec * 1000000 - time1->tv_usec; } +typedef struct { + uint8_t *data; + size_t size; +} buffer_t; + static int mlt_write(void *h, uint8_t *buf, int size) { mlt_properties properties = (mlt_properties) h; - mlt_events_fire( properties, "avformat-write", buf, &size, NULL ); + buffer_t buffer = { buf, size }; + mlt_events_fire( properties, "avformat-write", mlt_event_data_from_object(&buffer) ); return 0; } -static void write_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args ) -{ - int *p_size = (int*) args[1]; - listener( owner, service, (uint8_t*) args[0], *p_size ); -} - typedef struct encode_ctx_desc { mlt_consumer consumer; @@ -1426,7 +1427,7 @@ static int encode_audio(encode_ctx_t* ctx) if ( av_interleaved_write_frame( ctx->oc, &pkt ) ) { mlt_log_fatal( MLT_CONSUMER_SERVICE( ctx->consumer ), "error writing audio frame\n" ); - mlt_events_fire( ctx->properties, "consumer-fatal-error", NULL ); + mlt_events_fire( ctx->properties, "consumer-fatal-error", mlt_event_data_none() ); return -1; } ctx->error_count = 0; @@ -1673,12 +1674,12 @@ static void *consumer_thread( void *arg ) if ( !strcmp( pix_fmt_name, "rgba" ) || !strcmp( pix_fmt_name, "argb" ) || !strcmp( pix_fmt_name, "bgra" ) ) { - mlt_properties_set( properties, "mlt_image_format", "rgb24a" ); - img_fmt = mlt_image_rgb24a; + mlt_properties_set( properties, "mlt_image_format", "rgba" ); + img_fmt = mlt_image_rgba; } else if ( strstr( pix_fmt_name, "rgb" ) || strstr( pix_fmt_name, "bgr" ) ) { - mlt_properties_set( properties, "mlt_image_format", "rgb24" ); - img_fmt = mlt_image_rgb24; + mlt_properties_set( properties, "mlt_image_format", "rgb" ); + img_fmt = mlt_image_rgb; } } } @@ -1775,7 +1776,7 @@ static void *consumer_thread( void *arg ) enc_ctx->oc->flags |= AVFMT_FLAG_CUSTOM_IO; mlt_properties_set_data( properties, "avio_buffer", buffer, buffer_size, av_free, NULL ); mlt_properties_set_data( properties, "avio_context", io, 0, av_free, NULL ); - mlt_events_register( properties, "avformat-write", (mlt_transmitter) write_transmitter ); + mlt_events_register( properties, "avformat-write" ); } else { @@ -1789,7 +1790,7 @@ static void *consumer_thread( void *arg ) if ( avio_open( &enc_ctx->oc->pb, filename, AVIO_FLAG_WRITE ) < 0 ) { mlt_log_error( MLT_CONSUMER_SERVICE( consumer ), "Could not open '%s'\n", filename ); - mlt_events_fire( properties, "consumer-fatal-error", NULL ); + mlt_events_fire( properties, "consumer-fatal-error", mlt_event_data_none() ); goto on_fatal_error; } } @@ -1799,7 +1800,7 @@ static void *consumer_thread( void *arg ) // Last check - need at least one stream if ( !enc_ctx->audio_st[0] && !enc_ctx->video_st ) { - mlt_events_fire( properties, "consumer-fatal-error", NULL ); + mlt_events_fire( properties, "consumer-fatal-error", mlt_event_data_none() ); goto on_fatal_error; } @@ -1815,7 +1816,7 @@ static void *consumer_thread( void *arg ) converted_avframe = alloc_picture( pix_fmt, width, height ); if ( !converted_avframe ) { mlt_log_error( MLT_CONSUMER_SERVICE( consumer ), "failed to allocate video AVFrame\n" ); - mlt_events_fire( properties, "consumer-fatal-error", NULL ); + mlt_events_fire( properties, "consumer-fatal-error", mlt_event_data_none() ); goto on_fatal_error; } } @@ -1834,7 +1835,7 @@ static void *consumer_thread( void *arg ) #endif } else { mlt_log_error( MLT_CONSUMER_SERVICE(consumer), "failed to allocate audio AVFrame\n" ); - mlt_events_fire( properties, "consumer-fatal-error", NULL ); + mlt_events_fire( properties, "consumer-fatal-error", mlt_event_data_none() ); goto on_fatal_error; } } @@ -1875,7 +1876,7 @@ static void *consumer_thread( void *arg ) if ( avformat_write_header( enc_ctx->oc, NULL ) < 0 ) { mlt_log_error( MLT_CONSUMER_SERVICE( consumer ), "Could not write header '%s'\n", filename ); - mlt_events_fire( properties, "consumer-fatal-error", NULL ); + mlt_events_fire( properties, "consumer-fatal-error", mlt_event_data_none() ); goto on_fatal_error; } @@ -1914,8 +1915,9 @@ static void *consumer_thread( void *arg ) sample_fifo_append( enc_ctx->fifo, pcm, samples * enc_ctx->channels * enc_ctx->sample_bytes ); total_time += ( samples * 1000000 ) / enc_ctx->frequency; } - if ( !enc_ctx->video_st ) - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + if ( !enc_ctx->video_st ) { + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); + } } // Encode the image @@ -1979,40 +1981,56 @@ static void *consumer_thread( void *arg ) converted_avframe->data, converted_avframe->linesize); sws_freeContext( context ); - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); // Apply the alpha if applicable if ( !mlt_properties_get( properties, "mlt_image_format" ) || - strcmp( mlt_properties_get( properties, "mlt_image_format" ), "rgb24a" ) ) + strcmp( mlt_properties_get( properties, "mlt_image_format" ), "rgba" ) ) if ( c->pix_fmt == AV_PIX_FMT_RGBA || c->pix_fmt == AV_PIX_FMT_ARGB || c->pix_fmt == AV_PIX_FMT_BGRA ) { uint8_t *p; - uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); - register int n; - - for ( i = 0; i < height; i ++ ) + uint8_t *alpha = mlt_frame_get_alpha( frame ); + if ( alpha ) { - n = ( width + 7 ) / 8; - p = converted_avframe->data[ 0 ] + i * converted_avframe->linesize[ 0 ] + 3; + register int n; - switch( width % 8 ) + for ( i = 0; i < height; i ++ ) { - case 0: do { *p = *alpha++; p += 4; - case 7: *p = *alpha++; p += 4; - case 6: *p = *alpha++; p += 4; - case 5: *p = *alpha++; p += 4; - case 4: *p = *alpha++; p += 4; - case 3: *p = *alpha++; p += 4; - case 2: *p = *alpha++; p += 4; - case 1: *p = *alpha++; p += 4; - } - while( --n ); + n = ( width + 7 ) / 8; + p = converted_avframe->data[ 0 ] + i * converted_avframe->linesize[ 0 ] + 3; + + switch( width % 8 ) + { + case 0: do { *p = *alpha++; p += 4; + case 7: *p = *alpha++; p += 4; + case 6: *p = *alpha++; p += 4; + case 5: *p = *alpha++; p += 4; + case 4: *p = *alpha++; p += 4; + case 3: *p = *alpha++; p += 4; + case 2: *p = *alpha++; p += 4; + case 1: *p = *alpha++; p += 4; + } + while( --n ); + } + } + } + else + { + for ( i = 0; i < height; i ++ ) + { + int n = width; + uint8_t* p = converted_avframe->data[ 0 ] + i * converted_avframe->linesize[ 0 ] + 3; + while ( n ) + { + *p = 255; + p += 4; + n--; + } } } } - #if defined(AVFILTER) && LIBAVUTIL_VERSION_MAJOR >= 56 if (AV_PIX_FMT_VAAPI == c->pix_fmt) { AVFilterContext *vfilter_in = mlt_properties_get_data(properties, "vfilter_in", NULL); @@ -2142,7 +2160,7 @@ static void *consumer_thread( void *arg ) if ( ret ) { mlt_log_fatal( MLT_CONSUMER_SERVICE(consumer), "error writing video frame: %d\n", ret ); - mlt_events_fire( properties, "consumer-fatal-error", NULL ); + mlt_events_fire( properties, "consumer-fatal-error", mlt_event_data_none() ); goto on_fatal_error; } mlt_frame_close( frame ); @@ -2252,7 +2270,7 @@ static void *consumer_thread( void *arg ) if ( av_interleaved_write_frame( enc_ctx->oc, &pkt ) != 0 ) { mlt_log_fatal( MLT_CONSUMER_SERVICE(consumer), "error writing flushed video frame\n" ); - mlt_events_fire( properties, "consumer-fatal-error", NULL ); + mlt_events_fire( properties, "consumer-fatal-error", mlt_event_data_none() ); goto on_fatal_error; } } diff --git a/src/modules/avformat/factory.c b/src/modules/avformat/factory.c index e342ff700..cf80385a4 100644 --- a/src/modules/avformat/factory.c +++ b/src/modules/avformat/factory.c @@ -112,9 +112,9 @@ static void *create_service( mlt_profile profile, mlt_service_type type, const c #ifdef CODECS if ( !strncmp( id, "avformat", 8 ) ) { - if ( type == producer_type ) + if ( type == mlt_service_producer_type ) return producer_avformat_init( profile, id, arg ); - else if ( type == consumer_type ) + else if ( type == mlt_service_consumer_type ) return consumer_avformat_init( profile, arg ); } #endif @@ -294,35 +294,41 @@ static mlt_properties avformat_metadata( mlt_service_type type, const char *id, // Convert the service type to a string. switch ( type ) { - case consumer_type: + case mlt_service_consumer_type: service_type = "consumer"; break; - case filter_type: + case mlt_service_filter_type: service_type = "filter"; break; - case producer_type: + case mlt_service_producer_type: service_type = "producer"; break; - case transition_type: + case mlt_service_transition_type: service_type = "transition"; break; default: return NULL; } + + if ( type == mlt_service_producer_type && !strcmp( id, "avformat-novalidate" ) ) + { + id = "avformat"; + } + // Load the yaml file snprintf( file, PATH_MAX, "%s/avformat/%s_%s.yml", mlt_environment( "MLT_DATA" ), service_type, id ); result = mlt_properties_parse_yaml( file ); - if ( result && ( type == consumer_type || type == producer_type ) ) + if ( result && ( type == mlt_service_consumer_type || type == mlt_service_producer_type ) ) { // Annotate the yaml properties with AVOptions. mlt_properties params = (mlt_properties) mlt_properties_get_data( result, "parameters", NULL ); AVFormatContext *avformat = avformat_alloc_context(); AVCodecContext *avcodec = avcodec_alloc_context3( NULL ); - int flags = ( type == consumer_type )? AV_OPT_FLAG_ENCODING_PARAM : AV_OPT_FLAG_DECODING_PARAM; + int flags = ( type == mlt_service_consumer_type )? AV_OPT_FLAG_ENCODING_PARAM : AV_OPT_FLAG_DECODING_PARAM; add_parameters( params, avformat, flags, NULL, NULL, NULL ); avformat_init(); - if ( type == producer_type ) + if ( type == mlt_service_producer_type ) { AVInputFormat *f = NULL; while ( ( f = av_iformat_next( f ) ) ) @@ -420,17 +426,17 @@ static mlt_properties avfilter_metadata( mlt_service_type type, const char *id, MLT_REPOSITORY { #ifdef CODECS - MLT_REGISTER( consumer_type, "avformat", create_service ); - MLT_REGISTER( producer_type, "avformat", create_service ); - MLT_REGISTER( producer_type, "avformat-novalidate", create_service ); - MLT_REGISTER_METADATA( consumer_type, "avformat", avformat_metadata, NULL ); - MLT_REGISTER_METADATA( producer_type, "avformat", avformat_metadata, NULL ); + MLT_REGISTER( mlt_service_consumer_type, "avformat", create_service ); + MLT_REGISTER( mlt_service_producer_type, "avformat", create_service ); + 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 ); #endif #ifdef FILTERS - MLT_REGISTER( filter_type, "avcolour_space", create_service ); - MLT_REGISTER( filter_type, "avcolor_space", create_service ); - MLT_REGISTER( filter_type, "avdeinterlace", create_service ); - MLT_REGISTER( filter_type, "swscale", create_service ); + 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 ); #ifdef AVFILTER char dirname[PATH_MAX]; @@ -457,14 +463,14 @@ MLT_REPOSITORY { char service_name[1024]="avfilter."; strncat( service_name, f->name, sizeof( service_name ) - strlen( service_name ) -1 ); - MLT_REGISTER( filter_type, service_name, filter_avfilter_init ); - MLT_REGISTER_METADATA( filter_type, service_name, avfilter_metadata, (void*)f->name ); + MLT_REGISTER( mlt_service_filter_type, service_name, filter_avfilter_init ); + MLT_REGISTER_METADATA( mlt_service_filter_type, service_name, avfilter_metadata, (void*)f->name ); } } mlt_properties_close( blacklist ); #endif // AVFILTER #endif #ifdef SWRESAMPLE - MLT_REGISTER( filter_type, "swresample", create_service ); + MLT_REGISTER( mlt_service_filter_type, "swresample", create_service ); #endif } diff --git a/src/modules/avformat/filter_avcolour_space.c b/src/modules/avformat/filter_avcolour_space.c index 086afc436..b1bef701d 100644 --- a/src/modules/avformat/filter_avcolour_space.c +++ b/src/modules/avformat/filter_avcolour_space.c @@ -51,11 +51,10 @@ static int convert_mlt_to_av_cs( mlt_image_format format ) switch( format ) { - case mlt_image_rgb24: + case mlt_image_rgb: value = AV_PIX_FMT_RGB24; break; - case mlt_image_rgb24a: - case mlt_image_opengl: + case mlt_image_rgba: value = AV_PIX_FMT_RGBA; break; case mlt_image_yuv422: @@ -150,7 +149,7 @@ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *fo uint8_t *output = mlt_pool_alloc( size ); if (out_width == width && out_height == height) { - if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) + if ( *format == mlt_image_rgba ) { register int len = width * height; uint8_t *alpha = mlt_pool_alloc( len ); @@ -202,7 +201,7 @@ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *fo mlt_properties_set_int(properties, "height", out_height); if (out_width == width && out_height == height) - if ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl ) + if ( output_format == mlt_image_rgba ) { register int len = width * height; int alpha_size = 0; diff --git a/src/modules/avformat/filter_avfilter.c b/src/modules/avformat/filter_avfilter.c index 354991217..12d37936f 100644 --- a/src/modules/avformat/filter_avfilter.c +++ b/src/modules/avformat/filter_avfilter.c @@ -1,7 +1,6 @@ /* * filter_avfilter.c -- provide various filters based on libavfilter - * Copyright (C) 2016-2020 Meltytech, LLC - * Author: Brian Matherly + * Copyright (C) 2016-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 @@ -54,9 +53,10 @@ typedef struct int reset; } private_data; -static void property_changed( mlt_service owner, mlt_filter filter, char *name ) +static void property_changed( mlt_service owner, mlt_filter filter, mlt_event_data event_data ) { - if( strncmp( PARAM_PREFIX, name, PARAM_PREFIX_LEN ) == 0 ) { + const char *name = mlt_event_data_to_string(event_data); + if( name && strncmp( PARAM_PREFIX, name, PARAM_PREFIX_LEN ) == 0 ) { private_data* pdata = (private_data*)filter->child; if( pdata->avfilter ) { @@ -79,9 +79,9 @@ static int mlt_to_av_image_format( mlt_image_format format ) { case mlt_image_none: return AV_PIX_FMT_NONE; - case mlt_image_rgb24: + case mlt_image_rgb: return AV_PIX_FMT_RGB24; - case mlt_image_rgb24a: + case mlt_image_rgba: return AV_PIX_FMT_RGBA; case mlt_image_yuv422: return AV_PIX_FMT_YUYV422; @@ -97,19 +97,18 @@ static mlt_image_format get_supported_image_format( mlt_image_format format ) { switch( format ) { - case mlt_image_rgb24a: - return mlt_image_rgb24a; - case mlt_image_rgb24: - return mlt_image_rgb24; + case mlt_image_rgba: + return mlt_image_rgba; + case mlt_image_rgb: + return mlt_image_rgb; case mlt_image_yuv420p: return mlt_image_yuv420p; default: mlt_log_error(NULL, "[filter_avfilter] Unknown image format requested: %d\n", format ); case mlt_image_none: case mlt_image_yuv422: - case mlt_image_opengl: - case mlt_image_glsl: - case mlt_image_glsl_texture: + case mlt_image_movit: + case mlt_image_opengl_texture: return mlt_image_yuv422; } } @@ -758,7 +757,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format int i; uint8_t* src = *image; uint8_t* dst = pdata->avinframe->data[0]; - int stride = mlt_image_format_size( *format, *width, 0, NULL ); + int stride = mlt_image_format_size( *format, *width, 1, NULL ); for( i = 0; i < *height; i ++ ) { memcpy( dst, src, stride ); @@ -809,7 +808,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format int i; uint8_t* dst = *image; uint8_t* src = pdata->avoutframe->data[0]; - int stride = mlt_image_format_size( *format, *width, 0, NULL ); + int stride = mlt_image_format_size( *format, *width, 1, NULL ); for( i = 0; i < *height; i ++ ) { memcpy( dst, src, stride ); diff --git a/src/modules/avformat/filter_swresample.c b/src/modules/avformat/filter_swresample.c index 0978695d8..0d3a8478e 100644 --- a/src/modules/avformat/filter_swresample.c +++ b/src/modules/avformat/filter_swresample.c @@ -1,7 +1,6 @@ /* * filter_swresample.c -- convert from one format/ configuration to another * Copyright (C) 2018 Meltytech, LLC - * Author: Brian Matherly * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -206,9 +205,14 @@ static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *f mlt_audio_get_planes( &out, pdata->out_buffers ); int received_samples = swr_convert( pdata->ctx, pdata->out_buffers, out.samples, (const uint8_t**)pdata->in_buffers, in.samples ); - if( received_samples > 0 ) + if( received_samples >= 0 ) { - if( received_samples < requested_samples ) + if ( received_samples == 0 ) + { + mlt_log_info( MLT_FILTER_SERVICE(filter), "Precharge required - return silence\n" ); + mlt_audio_silence( &out, out.samples, 0 ); + } + else if( received_samples < requested_samples ) { // Duplicate samples to return the exact number requested. mlt_audio_copy( &out, &out, received_samples, 0, requested_samples - received_samples ); diff --git a/src/modules/avformat/filter_swscale.c b/src/modules/avformat/filter_swscale.c index 52c165f9f..1df8edd98 100644 --- a/src/modules/avformat/filter_swscale.c +++ b/src/modules/avformat/filter_swscale.c @@ -39,11 +39,10 @@ static inline int convert_mlt_to_av_cs( mlt_image_format format ) switch( format ) { - case mlt_image_rgb24: + case mlt_image_rgb: value = AV_PIX_FMT_RGB24; break; - case mlt_image_rgb24a: - case mlt_image_opengl: + case mlt_image_rgba: value = AV_PIX_FMT_RGBA; break; case mlt_image_yuv422: @@ -98,9 +97,8 @@ static int filter_scale( mlt_frame frame, uint8_t **image, mlt_image_format *for switch ( *format ) { case mlt_image_yuv422: - case mlt_image_rgb24: - case mlt_image_rgb24a: - case mlt_image_opengl: + case mlt_image_rgb: + case mlt_image_rgba: break; default: // XXX: we only know how to rescale packed formats diff --git a/src/modules/avformat/producer_avformat.c b/src/modules/avformat/producer_avformat.c index 049452f9d..0997c622b 100644 --- a/src/modules/avformat/producer_avformat.c +++ b/src/modules/avformat/producer_avformat.c @@ -1249,7 +1249,7 @@ static mlt_image_format pick_image_format( enum AVPixelFormat pix_fmt ) case AV_PIX_FMT_RGBA: case AV_PIX_FMT_ABGR: case AV_PIX_FMT_BGRA: - return mlt_image_rgb24a; + return mlt_image_rgba; case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUVJ420P: case AV_PIX_FMT_YUVA420P: @@ -1263,7 +1263,7 @@ static mlt_image_format pick_image_format( enum AVPixelFormat pix_fmt ) case AV_PIX_FMT_BGR8: #if defined(FFUDIV) case AV_PIX_FMT_BAYER_RGGB16LE: - return mlt_image_rgb24; + return mlt_image_rgb; #endif default: return mlt_image_yuv422; @@ -1449,7 +1449,7 @@ static int convert_image( producer_avformat self, AVFrame *frame, uint8_t *buffe || pix_fmt == AV_PIX_FMT_YUVA444P #endif ) && - *format != mlt_image_rgb24a && *format != mlt_image_opengl && + *format != mlt_image_rgba && frame->data[3] && frame->linesize[3] ) { int i; @@ -1495,7 +1495,7 @@ static int convert_image( producer_avformat self, AVFrame *frame, uint8_t *buffe out_data, out_stride); sws_freeContext( context ); } - else if ( *format == mlt_image_rgb24 ) + else if ( *format == mlt_image_rgb ) { int flags = mlt_get_sws_flags(width, height, src_pix_fmt, width, height, AV_PIX_FMT_RGB24); struct SwsContext *context = sws_getContext( width, height, src_pix_fmt, @@ -1509,7 +1509,7 @@ static int convert_image( producer_avformat self, AVFrame *frame, uint8_t *buffe out_data, out_stride); sws_freeContext( context ); } - else if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) + else if ( *format == mlt_image_rgba ) { int flags = mlt_get_sws_flags(width, height, src_pix_fmt, width, height, AV_PIX_FMT_RGBA); struct SwsContext *context = sws_getContext( width, height, src_pix_fmt, @@ -1761,7 +1761,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form stream = context->streams[ self->video_index ]; codec_context = stream->codec; codec_params = stream->codecpar; - if ( *format == mlt_image_none || *format == mlt_image_glsl || + 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 || @@ -1771,8 +1771,8 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form else if ( codec_params->format == AV_PIX_FMT_BAYER_RGGB16LE ) { if ( *format == mlt_image_yuv422 ) *format = mlt_image_yuv420p; - else if ( *format == mlt_image_rgb24a ) - *format = mlt_image_rgb24; + else if ( *format == mlt_image_rgba ) + *format = mlt_image_rgb; } #endif else if ( codec_params->format == AV_PIX_FMT_YUVA444P10LE @@ -1781,7 +1781,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form || codec_params->format == AV_PIX_FMT_GBRAP12LE #endif ) - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; // Duplicate the last image if necessary if ( self->video_frame && self->video_frame->linesize[0] @@ -2348,6 +2348,8 @@ static int video_codec_init( producer_avformat self, int index, mlt_properties p break; } + 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 ) diff --git a/src/modules/core/CMakeLists.txt b/src/modules/core/CMakeLists.txt index dca1acc5a..f2f270d94 100644 --- a/src/modules/core/CMakeLists.txt +++ b/src/modules/core/CMakeLists.txt @@ -10,8 +10,6 @@ add_library(mltcore MODULE filter_channelcopy.c filter_choppy.c filter_crop.c - filter_data_feed.c - filter_data_show.c filter_fieldorder.c filter_gamma.c filter_greyscale.c @@ -23,11 +21,11 @@ add_library(mltcore MODULE filter_mono.c filter_obscure.c filter_panner.c - filter_region.c filter_rescale.c filter_resize.c filter_transition.c filter_watermark.c + link_timeremap.c producer_colour.c producer_consumer.c producer_hold.c @@ -40,23 +38,29 @@ add_library(mltcore MODULE transition_luma.c transition_matte.c transition_mix.c - transition_region.c ) -target_link_libraries(mltcore mlt Threads::Threads) +target_compile_options(mltcore PRIVATE ${MLT_COMPILE_OPTIONS}) + +target_link_libraries(mltcore PRIVATE m mlt Threads::Threads) if(WIN32) target_sources(mltcore PRIVATE ../../win32/fnmatch.c) + target_include_directories(mltcore PRIVATE ../../win32) +endif() + +if(CPU_SSE) + target_compile_definitions(mltcore PRIVATE USE_SSE) endif() -if(X86_64) +if(CPU_X86_64) target_sources(mltcore PRIVATE composite_line_yuv_sse2_simple.c) + target_compile_definitions(mltcore PRIVATE ARCH_X86_64) endif() -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltcore PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +set_target_properties(mltcore PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(TARGETS mltcore LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +install(TARGETS mltcore LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES consumer_multi.yml @@ -66,7 +70,6 @@ install(FILES filter_channelcopy.yml filter_choppy.yml filter_crop.yml - filter_data_show.yml filter_fieldorder.yml filter_gamma.yml filter_greyscale.yml @@ -77,11 +80,11 @@ install(FILES filter_mono.yml filter_obscure.yml filter_panner.yml - filter_region.yml filter_rescale.yml filter_resize.yml filter_transition.yml filter_watermark.yml + link_timeremap.yml producer_colour.yml producer_consumer.yml producer_hold.yml @@ -95,9 +98,7 @@ install(FILES transition_luma.yml transition_matte.yml transition_mix.yml - transition_region.yml - data_fx.properties loader.dict loader.ini - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/core + DESTINATION ${MLT_INSTALL_DATA_DIR}/core ) diff --git a/src/modules/core/Makefile b/src/modules/core/Makefile index e524f990c..1ac5a1af0 100644 --- a/src/modules/core/Makefile +++ b/src/modules/core/Makefile @@ -23,8 +23,6 @@ OBJS = factory.o \ filter_channelcopy.o \ filter_choppy.o \ filter_crop.o \ - filter_data_feed.o \ - filter_data_show.o \ filter_fieldorder.o \ filter_gamma.o \ filter_greyscale.o \ @@ -36,15 +34,14 @@ OBJS = factory.o \ filter_mono.o \ filter_obscure.o \ filter_panner.o \ - filter_region.o \ filter_rescale.o \ filter_resize.o \ filter_transition.o \ filter_watermark.o \ + link_timeremap.o \ transition_composite.o \ transition_luma.o \ transition_mix.o \ - transition_region.o \ transition_matte.o \ consumer_multi.o \ consumer_null.o @@ -85,7 +82,6 @@ clean: install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" install -d "$(DESTDIR)$(mltdatadir)/core" - install -m 644 data_fx.properties "$(DESTDIR)$(mltdatadir)/core" install -m 644 loader.dict "$(DESTDIR)$(mltdatadir)/core" install -m 644 loader.ini "$(DESTDIR)$(mltdatadir)/core" install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/core" diff --git a/src/modules/core/consumer_multi.c b/src/modules/core/consumer_multi.c index edebf9bed..bc1b07e52 100644 --- a/src/modules/core/consumer_multi.c +++ b/src/modules/core/consumer_multi.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2019 Meltytech, LLC + * 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 @@ -157,9 +157,9 @@ static void attach_normalisers( mlt_profile profile, mlt_service service ) create_filter( profile, service, "audioconvert", &created ); } -static void on_frame_show( void *dummy, mlt_properties properties, mlt_frame frame ) +static void on_frame_show( void *dummy, mlt_properties properties, mlt_event_data event_data ) { - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", event_data ); } static mlt_consumer generate_consumer( mlt_consumer consumer, mlt_properties props, int index ) diff --git a/src/modules/core/consumer_null.c b/src/modules/core/consumer_null.c index 9ab2ce56c..540abf08b 100644 --- a/src/modules/core/consumer_null.c +++ b/src/modules/core/consumer_null.c @@ -1,6 +1,6 @@ /* * consumer_null.c -- a null consumer - * Copyright (C) 2003-2014 Meltytech, LLC + * Copyright (C) 2003-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 @@ -153,7 +153,7 @@ static void *consumer_thread( void *arg ) if ( frame != NULL ) { // Close the frame - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); mlt_frame_close( frame ); } } diff --git a/src/modules/core/data_fx.properties b/src/modules/core/data_fx.properties deleted file mode 100644 index 2a4c1bc4e..000000000 --- a/src/modules/core/data_fx.properties +++ /dev/null @@ -1,259 +0,0 @@ -# This properties file describes the fx available to the data_send and -# data_show filters -# -# Syntax is as follows: -# -# name= -# name.description= -# name.properties.= -# name.=value -# etc -# -# Typically, the is a 'region' and additional filters are -# included as properties using the normal region filter syntax. -# - -# -# The titles filter definition -# - -titles=region -.description=Titles -.properties.markup=filter[1].producer.markup -.type.markup=text -.period=2 -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.composite.geometry=5%,70%:90%x20% -.filter[0]=watermark -.filter[0].resource=colour:0x000000 -.filter[0].composite.geometry=0%,0%:100%x100%:0;5=0%,0%:100%x100%:40 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=Shotcut -.filter[1].composite.geometry=0%,0%:100%x100%:0;8=0%,0%:100%x100%:100 -.filter[1].composite.titles=1 - -# -# The top titles filter definition -# - -top-titles=region -.description=Top Titles -.properties.markup=filter[1].producer.markup -.type.markup=text -.period=2 -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.composite.geometry=5%,5%:90%x20% -.filter[0]=watermark -.filter[0].resource=colour:0x000000 -.filter[0].composite.geometry=0%,0%:100%x100%:0;5=0%,0%:100%x100%:40 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=Shotcut -.filter[1].composite.geometry=0%,0%:100%x100%:0;8=0%,0%:100%x100%:100 -.filter[1].composite.halign=centre -.filter[1].composite.titles=1 - -# -# OK - Silly example... -# - -tickertape=region -.description=Tickertape -.properties.markup=filter[1].producer.markup -.type.markup=text -.properties.length[0]=filter[1].composite.out -.composite.geometry=0%,93%:100%x7% -.filter[0]=watermark -.filter[0].resource=colour:0x000000 -.filter[0].composite.geometry=0%,0%:100%x100%:100 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=Shotcut -.filter[1].composite.geometry=100%,0%:300%x100%:100;-1=-300%,0%:300%x100%:100 -.filter[1].producer.family=San -.filter[1].producer.size=32 -.filter[1].composite.titles=1 - -# -# ETV Location -# - -location=region -.description=Titles -.properties.markup=filter[1].producer.markup -.type.markup=text -.period=2 -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.composite.geometry=0,80:230x30 -.filter[0]=watermark -.filter[0].resource=colour:0x6c010100 -.filter[0].composite.geometry=-100%,0%:100%x100%:100;25=0%,0%:100%x100%:100 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup= -.filter[1].producer.family=San -.filter[1].producer.size=24 -.filter[1].composite.geometry=0%,0%:100%x100%:0;24=0%,0%:100%x100%:0;49=0%,0%:100%x100%:100 -.filter[1].composite.titles=1 -.filter[1].composite.halign=right -.filter[1].composite.valign=center - -courtesy=region -.description=Titles -.properties.markup=filter[1].producer.markup -.type.markup=text -.period=2 -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.composite.geometry=0,115:230x30 -.filter[0]=watermark -.filter[0].resource=colour:0x6c010100 -.filter[0].composite.geometry=-100%,0%:100%x100%:0;12=-100%,0%:100%x100%:0;37=0%,0%:100%x100%:100 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=ETV Exclusive -.filter[1].producer.family=San -.filter[1].producer.size=24 -.filter[1].composite.geometry=0%,0%:100%x100%:0;37=0%,0%:100%x100%:0;61=0%,0%:100%x100%:100 -.filter[1].composite.titles=1 -.filter[1].composite.halign=right -.filter[1].composite.valign=right - -exclusive=region -.description=Exclusive -.period=2 -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.composite.geometry=0,115:230x30 -.filter[0]=watermark -.filter[0].resource=colour:0x6c010100 -.filter[0].composite.geometry=0%,0%:100%x100%:10;25=0%,0%:100%x100%:100 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=ETV Exclusive -.filter[1].producer.family=San -.filter[1].producer.size=24 -.filter[1].composite.geometry=0%,0%:100%x100%:10;25=0%,0%:100%x100%:100 -.filter[1].composite.titles=1 -.filter[1].composite.halign=right -.filter[1].composite.valign=right - -file_shot=region -.description=Titles -.period=2 -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.composite.geometry=590,160:80x25 -.filter[0]=watermark -.filter[0].resource=colour:0x6c010100 -.filter[0].composite.geometry=0%,0%:100%x100%:10;25=0%,0%:100%x100%:100 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=File Shot -.filter[1].producer.family=San -.filter[1].producer.size=18 -.filter[1].composite.geometry=0%,0%:100%x100%:15;25=0%,0%:100%x100%:100 -.filter[1].composite.titles=0 -.filter[1].composite.halign=centre -.filter[1].composite.valign=centre - -special=region -.description=Titles -.period=2 -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.composite.geometry=465,375:255x35 -.filter[0]=watermark -.filter[0].resource=colour:0x6c010100 -.filter[0].composite.geometry=100%,0%:100%x100%:0;49=100%,0%:100%x100%:0;74=0%,0%:100%x100%:100 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=Special -.filter[1].producer.family=San -.filter[1].producer.size=24 -.filter[1].composite.geometry=100%,0%:100%x100%:0;49=100%,0%:100%x100%:0;74=0%,0%:100%x100%:100 -.filter[1].composite.titles=1 -.filter[1].composite.halign=centre -.filter[1].composite.valign=centre - -ticker=region -.description=Tickertape -.properties.markup=filter[1].producer.markup -.type.markup=text -.properties.length[0]=filter[1].composite.out -.composite.geometry=0,500:722x75 -.filter[0]=watermark -.filter[0].resource=colour:0x6c010100 -.filter[0].composite.geometry=0%,0%:100%x100%:100 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=Ticker - provided for reference -.filter[1].composite.geometry=0%,0%:100%x100%:100 -.filter[1].composite.titles=0 -.filter[1].producer.family=San -.filter[1].producer.size=24 -.filter[1].composite.halign=centre -.filter[1].composite.titles=1 -.filter[1].composite.valign=centre - -super=region -.description=Transcription -.properties.0=filter[1].producer.markup -.properties.1=filter[2].producer.markup -.properties.align=filter[1].composite.valign -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.properties.length[2]=filter[2].composite.out -.period=2 -.composite.geometry=0,410:720x90 -.filter[0]=watermark -.filter[0].resource=colour:0xbbbbbb00 -.filter[0].composite.geometry=0%,0%:100%x100%:10;25=0%,0%:100%x100%:100 -.filter[0].composite.titles=1 -.filter[0].composite.luma=%luma18.pgm -.filter[0].composite.out=25 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup= -.filter[1].producer.family=San -.filter[1].producer.size=32 -.filter[1].producer.fgcolour=0x6c0101ff -.filter[1].composite.geometry=0%,0%:100%x100%:10;25=0%,0%:100%x100%:100 -.filter[1].composite.titles=1 -.filter[1].composite.halign=centre -.filter[1].composite.valign=top -.filter[2]=watermark -.filter[2].resource=pango: -.filter[2].producer.markup= -.filter[1].producer.family=San -.filter[1].producer.size=32 -.filter[2].producer.fgcolour=0x6c0101ff -.filter[2].composite.geometry=0%,0%:100%x100%:10;25=0%,0%:100%x100%:100 -.filter[2].composite.titles=1 -.filter[2].composite.halign=centre -.filter[2].composite.valign=bottom - -obscure=region -.description=Obscure -.properties.geometry=composite.geometry -.properties.resource=resource -.properties.length[0]=composite.out -.composite.geometry= -.resource=rectangle -.composite.refresh=1 -.filter[0]=obscure -.filter[0].start=0,0:100%x100% - diff --git a/src/modules/core/factory.c b/src/modules/core/factory.c index c959f424d..b506f6507 100644 --- a/src/modules/core/factory.c +++ b/src/modules/core/factory.c @@ -31,8 +31,6 @@ extern mlt_filter filter_brightness_init( mlt_profile profile, mlt_service_type 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); extern mlt_filter filter_crop_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -extern mlt_filter filter_data_feed_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -extern mlt_filter filter_data_show_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_fieldorder_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_gamma_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_greyscale_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); @@ -44,11 +42,11 @@ extern mlt_filter filter_mirror_init( mlt_profile profile, mlt_service_type type 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_region_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 ); extern mlt_filter filter_watermark_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +extern mlt_link link_timeremap_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_colour_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_consumer_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_hold_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); @@ -62,7 +60,6 @@ extern mlt_producer producer_tone_init( mlt_profile profile, mlt_service_type ty extern mlt_transition transition_luma_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_transition transition_mix_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_transition transition_matte_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -#include "transition_region.h" static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { @@ -73,91 +70,86 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( consumer_type, "multi", consumer_multi_init ); - MLT_REGISTER( consumer_type, "null", consumer_null_init ); - MLT_REGISTER( filter_type, "audiochannels", filter_audiochannels_init ); - MLT_REGISTER( filter_type, "audioconvert", filter_audioconvert_init ); - MLT_REGISTER( filter_type, "audiomap", filter_audiomap_init ); - MLT_REGISTER( filter_type, "audiowave", filter_audiowave_init ); - MLT_REGISTER( filter_type, "brightness", filter_brightness_init ); - MLT_REGISTER( filter_type, "channelcopy", filter_channelcopy_init ); - MLT_REGISTER( filter_type, "channelswap", filter_channelcopy_init ); - MLT_REGISTER( filter_type, "choppy", filter_choppy_init ); - MLT_REGISTER( filter_type, "crop", filter_crop_init ); - MLT_REGISTER( filter_type, "data_feed", filter_data_feed_init ); - MLT_REGISTER( filter_type, "data_show", filter_data_show_init ); - MLT_REGISTER( filter_type, "fieldorder", filter_fieldorder_init ); - MLT_REGISTER( filter_type, "gamma", filter_gamma_init ); - MLT_REGISTER( filter_type, "greyscale", filter_greyscale_init ); - MLT_REGISTER( filter_type, "grayscale", filter_greyscale_init ); - MLT_REGISTER( filter_type, "imageconvert", filter_imageconvert_init ); - MLT_REGISTER( filter_type, "luma", filter_luma_init ); - MLT_REGISTER( filter_type, "mask_apply", filter_mask_apply_init ); - MLT_REGISTER( filter_type, "mask_start", filter_mask_start_init ); - MLT_REGISTER( filter_type, "mirror", filter_mirror_init ); - MLT_REGISTER( filter_type, "mono", filter_mono_init ); - MLT_REGISTER( filter_type, "obscure", filter_obscure_init ); - MLT_REGISTER( filter_type, "panner", filter_panner_init ); - MLT_REGISTER( filter_type, "region", filter_region_init ); - MLT_REGISTER( filter_type, "rescale", filter_rescale_init ); - MLT_REGISTER( filter_type, "resize", filter_resize_init ); - MLT_REGISTER( filter_type, "transition", filter_transition_init ); - MLT_REGISTER( filter_type, "watermark", filter_watermark_init ); - MLT_REGISTER( producer_type, "abnormal", producer_loader_init ); - MLT_REGISTER( producer_type, "color", producer_colour_init ); - MLT_REGISTER( producer_type, "colour", producer_colour_init ); - MLT_REGISTER( producer_type, "consumer", producer_consumer_init ); - MLT_REGISTER( producer_type, "hold", producer_hold_init ); - MLT_REGISTER( producer_type, "loader", producer_loader_init ); - MLT_REGISTER( producer_type, "melt", producer_melt_init ); - MLT_REGISTER( producer_type, "melt_file", producer_melt_file_init ); - MLT_REGISTER( producer_type, "noise", producer_noise_init ); - MLT_REGISTER( producer_type, "timewarp", producer_timewarp_init ); - MLT_REGISTER( producer_type, "tone", producer_tone_init ); - MLT_REGISTER( transition_type, "composite", transition_composite_init ); - MLT_REGISTER( transition_type, "luma", transition_luma_init ); - MLT_REGISTER( transition_type, "mix", transition_mix_init ); - MLT_REGISTER( transition_type, "matte", transition_matte_init ); - MLT_REGISTER( transition_type, "region", transition_region_init ); + MLT_REGISTER( mlt_service_consumer_type, "multi", consumer_multi_init ); + MLT_REGISTER( mlt_service_consumer_type, "null", consumer_null_init ); + MLT_REGISTER( mlt_service_filter_type, "audiochannels", filter_audiochannels_init ); + 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, "brightness", filter_brightness_init ); + MLT_REGISTER( mlt_service_filter_type, "channelcopy", filter_channelcopy_init ); + MLT_REGISTER( mlt_service_filter_type, "channelswap", filter_channelcopy_init ); + MLT_REGISTER( mlt_service_filter_type, "choppy", filter_choppy_init ); + MLT_REGISTER( mlt_service_filter_type, "crop", filter_crop_init ); + MLT_REGISTER( mlt_service_filter_type, "fieldorder", filter_fieldorder_init ); + MLT_REGISTER( mlt_service_filter_type, "gamma", filter_gamma_init ); + MLT_REGISTER( mlt_service_filter_type, "greyscale", filter_greyscale_init ); + MLT_REGISTER( mlt_service_filter_type, "grayscale", filter_greyscale_init ); + MLT_REGISTER( mlt_service_filter_type, "imageconvert", filter_imageconvert_init ); + MLT_REGISTER( mlt_service_filter_type, "luma", filter_luma_init ); + MLT_REGISTER( mlt_service_filter_type, "mask_apply", filter_mask_apply_init ); + MLT_REGISTER( mlt_service_filter_type, "mask_start", filter_mask_start_init ); + MLT_REGISTER( mlt_service_filter_type, "mirror", filter_mirror_init ); + 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, "rescale", filter_rescale_init ); + MLT_REGISTER( mlt_service_filter_type, "resize", filter_resize_init ); + MLT_REGISTER( mlt_service_filter_type, "transition", filter_transition_init ); + MLT_REGISTER( mlt_service_filter_type, "watermark", filter_watermark_init ); + MLT_REGISTER( mlt_service_link_type, "timeremap", link_timeremap_init ); + MLT_REGISTER( mlt_service_producer_type, "abnormal", producer_loader_init ); + MLT_REGISTER( mlt_service_producer_type, "color", producer_colour_init ); + MLT_REGISTER( mlt_service_producer_type, "colour", producer_colour_init ); + MLT_REGISTER( mlt_service_producer_type, "consumer", producer_consumer_init ); + MLT_REGISTER( mlt_service_producer_type, "hold", producer_hold_init ); + MLT_REGISTER( mlt_service_producer_type, "loader", producer_loader_init ); + MLT_REGISTER( mlt_service_producer_type, "melt", producer_melt_init ); + MLT_REGISTER( mlt_service_producer_type, "melt_file", producer_melt_file_init ); + MLT_REGISTER( mlt_service_producer_type, "noise", producer_noise_init ); + MLT_REGISTER( mlt_service_producer_type, "timewarp", producer_timewarp_init ); + MLT_REGISTER( mlt_service_producer_type, "tone", producer_tone_init ); + MLT_REGISTER( mlt_service_transition_type, "composite", transition_composite_init ); + MLT_REGISTER( mlt_service_transition_type, "luma", transition_luma_init ); + MLT_REGISTER( mlt_service_transition_type, "mix", transition_mix_init ); + MLT_REGISTER( mlt_service_transition_type, "matte", transition_matte_init ); - MLT_REGISTER_METADATA( consumer_type, "multi", metadata, "consumer_multi.yml" ); - MLT_REGISTER_METADATA( filter_type, "audiomap", metadata, "filter_audiomap.yml" ); - MLT_REGISTER_METADATA( filter_type, "audiowave", metadata, "filter_audiowave.yml" ); - MLT_REGISTER_METADATA( filter_type, "brightness", metadata, "filter_brightness.yml" ); - MLT_REGISTER_METADATA( filter_type, "channelcopy", metadata, "filter_channelcopy.yml" ); - MLT_REGISTER_METADATA( filter_type, "channelswap", metadata, "filter_channelcopy.yml" ); - MLT_REGISTER_METADATA( filter_type, "choppy", metadata, "filter_choppy.yml" ); - MLT_REGISTER_METADATA( filter_type, "crop", metadata, "filter_crop.yml" ); - MLT_REGISTER_METADATA( filter_type, "data_show", metadata, "filter_data_show.yml" ); - MLT_REGISTER_METADATA( filter_type, "fieldorder", metadata, "filter_fieldorder.yml" ); - MLT_REGISTER_METADATA( filter_type, "gamma", metadata, "filter_gamma.yml" ); - MLT_REGISTER_METADATA( filter_type, "greyscale", metadata, "filter_greyscale.yml" ); - MLT_REGISTER_METADATA( filter_type, "grayscale", metadata, "filter_greyscale.yml" ); - MLT_REGISTER_METADATA( filter_type, "luma", metadata, "filter_luma.yml" ); - MLT_REGISTER_METADATA( filter_type, "mask_apply", metadata, "filter_mask_apply.yml" ); - MLT_REGISTER_METADATA( filter_type, "mask_start", metadata, "filter_mask_start.yml" ); - MLT_REGISTER_METADATA( filter_type, "mirror", metadata, "filter_mirror.yml" ); - MLT_REGISTER_METADATA( filter_type, "mono", metadata, "filter_mono.yml" ); - MLT_REGISTER_METADATA( filter_type, "obscure", metadata, "filter_obscure.yml" ); - MLT_REGISTER_METADATA( filter_type, "panner", metadata, "filter_panner.yml" ); - MLT_REGISTER_METADATA( filter_type, "region", metadata, "filter_region.yml" ); - MLT_REGISTER_METADATA( filter_type, "rescale", metadata, "filter_rescale.yml" ); - MLT_REGISTER_METADATA( filter_type, "resize", metadata, "filter_resize.yml" ); - MLT_REGISTER_METADATA( filter_type, "transition", metadata, "filter_transition.yml" ); - MLT_REGISTER_METADATA( filter_type, "watermark", metadata, "filter_watermark.yml" ); - MLT_REGISTER_METADATA( producer_type, "colour", metadata, "producer_colour.yml" ); - MLT_REGISTER_METADATA( producer_type, "color", metadata, "producer_colour.yml" ); - MLT_REGISTER_METADATA( producer_type, "consumer", metadata, "producer_consumer.yml" ); - MLT_REGISTER_METADATA( producer_type, "hold", metadata, "producer_hold.yml" ); - MLT_REGISTER_METADATA( producer_type, "loader", metadata, "producer_loader.yml" ); - MLT_REGISTER_METADATA( producer_type, "melt", metadata, "producer_melt.yml" ); - MLT_REGISTER_METADATA( producer_type, "melt_file", metadata, "producer_melt_file.yml" ); - MLT_REGISTER_METADATA( producer_type, "noise", metadata, "producer_noise.yml" ); - MLT_REGISTER_METADATA( producer_type, "timewarp", metadata, "producer_timewarp.yml" ); - MLT_REGISTER_METADATA( producer_type, "tone", metadata, "producer_tone.yml" ); - MLT_REGISTER_METADATA( transition_type, "composite", metadata, "transition_composite.yml" ); - MLT_REGISTER_METADATA( transition_type, "luma", metadata, "transition_luma.yml" ); - MLT_REGISTER_METADATA( transition_type, "mix", metadata, "transition_mix.yml" ); - MLT_REGISTER_METADATA( transition_type, "matte", metadata, "transition_matte.yml" ); - MLT_REGISTER_METADATA( transition_type, "region", metadata, "transition_region.yml" ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "multi", metadata, "consumer_multi.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, "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" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "choppy", metadata, "filter_choppy.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "crop", metadata, "filter_crop.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "fieldorder", metadata, "filter_fieldorder.yml" ); + 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, "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" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "mirror", metadata, "filter_mirror.yml" ); + 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, "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, "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" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "hold", metadata, "producer_hold.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "loader", metadata, "producer_loader.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "melt", metadata, "producer_melt.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "melt_file", metadata, "producer_melt_file.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "noise", metadata, "producer_noise.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "timewarp", metadata, "producer_timewarp.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "tone", metadata, "producer_tone.yml" ); + MLT_REGISTER_METADATA( mlt_service_transition_type, "composite", metadata, "transition_composite.yml" ); + MLT_REGISTER_METADATA( mlt_service_transition_type, "luma", metadata, "transition_luma.yml" ); + MLT_REGISTER_METADATA( mlt_service_transition_type, "mix", metadata, "transition_mix.yml" ); + MLT_REGISTER_METADATA( mlt_service_transition_type, "matte", metadata, "transition_matte.yml" ); } diff --git a/src/modules/core/filter_audiowave.yml b/src/modules/core/filter_audiowave.yml index b3f3dd9e7..8aa9e3c41 100644 --- a/src/modules/core/filter_audiowave.yml +++ b/src/modules/core/filter_audiowave.yml @@ -1,13 +1,15 @@ schema_version: 0.1 type: filter identifier: audiowave -title: Audio Waveform +title: Audio Waveform (*deprecated*) version: 1 copyright: Meltytech, LLC creator: Dan Dennedy license: LGPLv2.1 language: en description: Generate audio waveforms. +notes: > + This filter is deprecated and will eventually be removed. Use the audiowaveform filter instead. tags: - Video bugs: diff --git a/src/modules/core/filter_brightness.c b/src/modules/core/filter_brightness.c index 8f43f0f31..413a17e89 100644 --- a/src/modules/core/filter_brightness.c +++ b/src/modules/core/filter_brightness.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -28,49 +29,56 @@ struct sliced_desc { - uint8_t *image; - int rgba; - int width, height; + mlt_image image; double level; double alpha_level; - uint8_t* alpha; }; 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.height + jobs - 1) / jobs; - int slice_offset = index * slice_height * ctx.width; - slice_height = MIN(slice_height, ctx.height - index * slice_height); + 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); // Only process if level is something other than 1 - if (ctx.level != 1.0) { - int i = ctx.width * slice_height + 1; - uint8_t *p = ctx.image + (slice_offset * 2); - int32_t m = ctx.level * (1 << 16); + if (ctx->level != 1.0 && ctx->image->format == mlt_image_yuv422) { + int32_t m = ctx->level * (1 << 16); int32_t n = 128 * ((1 << 16 ) - m); - - for (; --i; p += 2) { - p[0] = CLAMP((p[0] * m) >> 16, 16, 235); - p[1] = CLAMP((p[1] * m + n) >> 16, 16, 240); + for ( int line = 0; line < slice_height; line++ ) + { + 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); + } } + } // Process the alpha channel if requested. - if (ctx.alpha_level != 1.0) { - int32_t m = ctx.alpha_level * (1 << 16); - int i = ctx.width * slice_height + 1; - - if (ctx.rgba) { - uint8_t *p = ctx.image + (slice_offset * 4) + 3; - for (; --i; p += 4) { - p[0] = (p[0] * m) >> 16; + if (ctx->alpha_level != 1.0) { + int32_t m = ctx->alpha_level * (1 << 16); + if (ctx->image->format == mlt_image_rgba) { + for ( int line = 0; line < slice_height; line++ ) + { + uint8_t* p = ctx->image->planes[0] + ( (slice_line_start + line) * ctx->image->strides[0]) + 3; + for ( int pixel = 0; pixel < ctx->image->width; pixel++ ) + { + *p = (*p * m) >> 16; + p += 4; + } } } else { - uint8_t *p = ctx.alpha + slice_offset; - for (; --i; ++p) { - p[0] = (p[0] * m) >> 16; + for ( int line = 0; line < slice_height; line++ ) + { + uint8_t* p = ctx->image->planes[3] + ( (slice_line_start + line) * ctx->image->strides[3]); + for ( int pixel = 0; pixel < ctx->image->width; pixel++ ) + { + *p++ = (*p * m) >> 16; + } } } } @@ -87,6 +95,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); double level = 1.0; + double alpha_level = 1.0; // Use animated "level" property only if it has been set since init char* level_property = mlt_properties_get( properties, "level" ); @@ -116,20 +125,33 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format // Get the image int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); + level = (*format == mlt_image_yuv422) ? level : 1.0; + alpha_level = mlt_properties_get(properties, "alpha")? MIN(mlt_properties_anim_get_double(properties, "alpha", position, length), 1.0) : 1.0; + if (alpha_level < 0.0) { + alpha_level = level; + } + // Only process if we have no error. - if (!error) { + if (!error && (level != 1.0 || alpha_level != 1.0)) { int threads = mlt_properties_get_int(properties, "threads"); + struct sliced_desc desc; + struct mlt_image_s proc_image; + mlt_image_set_values( &proc_image, *image, *format, *width, *height ); + if (alpha_level != 1.0 && proc_image.format != mlt_image_rgba) { + proc_image.planes[3] = mlt_frame_get_alpha(frame); + proc_image.strides[3] = proc_image.width; + if (!proc_image.planes[3]) { + // Alpha will be needed but it does not exist yet. Create opaque alpha. + mlt_image_alloc_alpha( &proc_image ); + mlt_image_fill_opaque( &proc_image ); + mlt_frame_set_alpha( frame, proc_image.planes[3], 0, proc_image.release_alpha ); + } + } + desc.level = level; + desc.alpha_level = alpha_level; + desc.image = &proc_image; + threads = CLAMP(threads, 0, mlt_slices_count_normal()); - double alpha = mlt_properties_get(properties, "alpha")? MIN(mlt_properties_anim_get_double(properties, "alpha", position, length), 1.0) : 1.0; - struct sliced_desc desc = { - .image = *image, - .rgba = (*format == mlt_image_rgb24a), - .width = *width, - .height = *height, - .level = (*format == mlt_image_yuv422)? level : 1.0, - .alpha_level = alpha >= 0.0 ? alpha : level, - .alpha = mlt_frame_get_alpha_mask(frame) - }; if (threads == 1) { sliced_proc(0, 0, 1, &desc); } else { diff --git a/src/modules/core/filter_crop.c b/src/modules/core/filter_crop.c index 80e3ac473..b1ba219c3 100644 --- a/src/modules/core/filter_crop.c +++ b/src/modules/core/filter_crop.c @@ -88,7 +88,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format // Subsampled YUV is messy and less precise. if (*format == mlt_image_yuv422 && frame->convert_image && (left & 1 || right & 1)) { - mlt_image_format requested_format = mlt_image_rgb24; + mlt_image_format requested_format = mlt_image_rgb; frame->convert_image( frame, image, format, requested_format ); } diff --git a/src/modules/core/filter_data_feed.c b/src/modules/core/filter_data_feed.c deleted file mode 100644 index aab144a21..000000000 --- a/src/modules/core/filter_data_feed.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * filter_data_feed.c -- data feed filter - * Copyright (C) 2004-2014 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 - -/** This filter should be used in conjunction with the data_show filter. - The concept of the data_feed is that it can be used to pass titles - or images to render on the frame, but doesn't actually do it - itself. data_feed imposes few rules on what's passed on and the - validity is confirmed in data_show before use. -*/ - -/** Data queue destructor. -*/ - -static void destroy_data_queue( void *arg ) -{ - if ( arg != NULL ) - { - // Assign the correct type - mlt_deque queue = arg; - - // Iterate through each item and destroy them - while ( mlt_deque_peek_front( queue ) != NULL ) - mlt_properties_close( mlt_deque_pop_back( queue ) ); - - // Close the deque - mlt_deque_close( queue ); - } -} - -/** Filter processing. -*/ - -static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) -{ - // Get the filter properties - mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); - - // Get the frame properties - mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); - - // Get the data queue - mlt_deque data_queue = mlt_properties_get_data( frame_properties, "data_queue", NULL ); - - // Get the type of the data feed - char *type = mlt_properties_get( filter_properties, "type" ); - - // Get the in and out points of this filter - int in = mlt_filter_get_in( filter ); - int out = mlt_filter_get_out( filter ); - - // Create the data queue if it doesn't exist - if ( data_queue == NULL ) - { - // Create the queue - data_queue = mlt_deque_init( ); - - // Assign it to the frame with the destructor - mlt_properties_set_data( frame_properties, "data_queue", data_queue, 0, destroy_data_queue, NULL ); - } - - // Now create the data feed - if ( data_queue != NULL && type != NULL && !strcmp( type, "attr_check" ) ) - { - int i = 0; - int count = mlt_properties_count( frame_properties ); - - for ( i = 0; i < count; i ++ ) - { - char *name = mlt_properties_get_name( frame_properties, i ); - - // Only deal with meta.attr.name values here - these should have a value of 1 to be considered - // Additional properties of the form are meta.attr.name.property are passed down on the feed - if ( !strncmp( name, "meta.attr.", 10 ) && strchr( name + 10, '.' ) == NULL && mlt_properties_get_int( frame_properties, name ) == 1 ) - { - // Temp var to hold name + '.' for pass method - char temp[ 132 ]; - - // Create a new data feed - mlt_properties feed = mlt_properties_new( ); - - // Assign it the base properties - mlt_properties_set( feed, "id", mlt_properties_get( filter_properties, "_unique_id" ) ); - mlt_properties_set( feed, "type", strrchr( name, '.' ) + 1 ); - mlt_properties_set_position( feed, "position", mlt_frame_get_position( frame ) ); - - // Assign in/out of service we're connected to - mlt_properties_set_position( feed, "in", mlt_properties_get_position( frame_properties, "in" ) ); - mlt_properties_set_position( feed, "out", mlt_properties_get_position( frame_properties, "out" ) ); - - // Pass all meta properties - sprintf( temp, "%s.", name ); - mlt_properties_pass( feed, frame_properties, temp ); - - // Push it on to the queue - mlt_deque_push_back( data_queue, feed ); - - // Make sure this attribute only gets processed once - mlt_properties_set_int( frame_properties, name, 0 ); - } - } - } - else if ( data_queue != NULL ) - { - // Create a new data feed - mlt_properties feed = mlt_properties_new( ); - - // Assign it the base properties - mlt_properties_set( feed, "id", mlt_properties_get( filter_properties, "_unique_id" ) ); - mlt_properties_set( feed, "type", type ); - mlt_properties_set_position( feed, "position", mlt_frame_get_position( frame ) ); - - // Assign in/out of service we're connected to - mlt_properties_set_position( feed, "in", mlt_properties_get_position( frame_properties, "in" ) ); - mlt_properties_set_position( feed, "out", mlt_properties_get_position( frame_properties, "out" ) ); - - // Correct in/out to the filter if specified - if ( in != 0 ) - mlt_properties_set_position( feed, "in", in ); - if ( out != 0 ) - mlt_properties_set_position( feed, "out", out ); - - // Pass the properties which start with a "feed." prefix - // Note that 'feed.text' in the filter properties becomes 'text' on the feed - mlt_properties_pass( feed, filter_properties, "feed." ); - - // Push it on to the queue - mlt_deque_push_back( data_queue, feed ); - } - - return frame; -} - -/** Constructor for the filter. -*/ - -mlt_filter filter_data_feed_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - // Create the filter - mlt_filter filter = mlt_filter_new( ); - - // Initialise it - if ( filter != NULL ) - { - // Get the properties - mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); - - // Assign the argument (default to titles) - mlt_properties_set( properties, "type", arg == NULL ? "titles" : arg ); - - // Specify the processing method - filter->process = filter_process; - } - - return filter; -} - diff --git a/src/modules/core/filter_data_show.c b/src/modules/core/filter_data_show.c deleted file mode 100644 index e0282d626..000000000 --- a/src/modules/core/filter_data_show.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * filter_data_show.c -- data feed filter - * Copyright (C) 2004-2014 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 - -/** Handle the profile. -*/ - -static mlt_filter obtain_filter( mlt_filter filter, char *type ) -{ - // Result to return - mlt_filter result = NULL; - - // Miscellaneous variable - int i = 0; - int type_len = strlen( type ); - - // Get the properties of the data show filter - mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); - - // Get the profile properties - mlt_properties profile_properties = mlt_properties_get_data( filter_properties, "profile_properties", NULL ); - - // Obtain the profile_properties if we haven't already - if ( profile_properties == NULL ) - { - char temp[ 512 ]; - - // Get the profile requested - char *profile = mlt_properties_get( filter_properties, "resource" ); - - // If none is specified, pick up the default for this normalisation - if ( profile == NULL ) - sprintf( temp, "%s/feeds/%s/data_fx.properties", mlt_environment( "MLT_DATA" ), mlt_environment( "MLT_NORMALISATION" ) ); - else if ( strchr( profile, '%' ) ) - sprintf( temp, "%s/feeds/%s/%s", mlt_environment( "MLT_DATA" ), mlt_environment( "MLT_NORMALISATION" ), strchr( profile, '%' ) + 1 ); - else - { - strncpy( temp, profile, sizeof( temp ) ); - temp[ sizeof( temp ) - 1 ] = '\0'; - } - - // Load the specified profile or use the default - profile_properties = mlt_properties_load( temp ); - - // Store for later retrieval - mlt_properties_set_data( filter_properties, "profile_properties", profile_properties, 0, ( mlt_destructor )mlt_properties_close, NULL ); - } - - if ( profile_properties != NULL ) - { - for ( i = 0; i < mlt_properties_count( profile_properties ); i ++ ) - { - char *name = mlt_properties_get_name( profile_properties, i ); - char *value = mlt_properties_get_value( profile_properties, i ); - - if ( result == NULL && !strcmp( name, type ) && result == NULL ) - result = mlt_factory_filter( mlt_service_profile( MLT_FILTER_SERVICE( filter ) ), value, NULL ); - else if ( result != NULL && !strncmp( name, type, type_len ) && name[ type_len ] == '.' ) - mlt_properties_set( MLT_FILTER_PROPERTIES( result ), name + type_len + 1, value ); - else if ( result != NULL ) - break; - } - } - - return result; -} - -/** Retrieve medatata value -*/ - -char* metadata_value(mlt_properties properties, char* name) -{ - if (name == NULL) return NULL; - char *meta = malloc( strlen(name) + 18 ); - sprintf( meta, "meta.attr.%s.markup", name); - char *result = mlt_properties_get( properties, meta); - free(meta); - return result; -} - -/** Convert frames to Timecode -*/ - -char* frame_to_timecode( int frames, double fps) -{ - if (fps == 0) return strdup("-"); - char *res = malloc(12); - int seconds = frames / fps; - frames = frames % lrint( fps ); - int minutes = seconds / 60; - seconds = seconds % 60; - int hours = minutes / 60; - minutes = minutes % 60; - sprintf(res, "%.2d:%.2d:%.2d:%.2d", hours, minutes, seconds, frames); - return res; -} - -/** Process the frame for the requested type -*/ - -static int process_feed( mlt_properties feed, mlt_filter filter, mlt_frame frame ) -{ - // Error return - int error = 1; - - // Get the properties of the data show filter - mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); - - // Get the type requested by the feeding filter - char *type = mlt_properties_get( feed, "type" ); - - // Fetch the filter associated to this type - mlt_filter requested = mlt_properties_get_data( filter_properties, type, NULL ); - - // If it doesn't exist, then create it now - if ( requested == NULL ) - { - // Source filter from profile - requested = obtain_filter( filter, type ); - - // Store it on the properties for subsequent retrieval/destruction - mlt_properties_set_data( filter_properties, type, requested, 0, ( mlt_destructor )mlt_filter_close, NULL ); - } - - // If we have one, then process it now... - if ( requested != NULL ) - { - int i = 0; - mlt_properties properties = MLT_FILTER_PROPERTIES( requested ); - static const char *prefix = "properties."; - int len = strlen( prefix ); - - // Determine if this is an absolute or relative feed - int absolute = mlt_properties_get_int( feed, "absolute" ); - - // Make do with what we have - int length = !absolute ? - mlt_properties_get_int( feed, "out" ) - mlt_properties_get_int( feed, "in" ) + 1 : - mlt_properties_get_int( feed, "out" ) + 1; - - // Repeat period - int period = mlt_properties_get_int( properties, "period" ); - period = period == 0 ? 1 : period; - - // Pass properties from feed into requested - for ( i = 0; i < mlt_properties_count( properties ); i ++ ) - { - char *name = mlt_properties_get_name( properties, i ); - char *key = mlt_properties_get_value( properties, i ); - if ( !strncmp( name, prefix, len ) ) - { - if ( !strncmp( name + len, "length[", 7 ) ) - { - mlt_properties_set_position( properties, key, ( length - period ) / period ); - } - else - { - char *value = mlt_properties_get( feed, name + len ); - if ( value != NULL ) - { - // check for metadata keywords in metadata markup if user requested so - if ( mlt_properties_get_int( filter_properties, "dynamic" ) == 1 && !strcmp( name + strlen( name ) - 6, "markup") ) - { - // Find keywords which should be surrounded by '#', like: #title# - char* keywords = strtok( value, "#" ); - char result[512] = ""; // XXX: how much is enough? - int ct = 0; - int fromStart = ( value[0] == '#' ) ? 1 : 0; - - while ( keywords != NULL ) - { - if ( ct % 2 == fromStart ) - { - // backslash in front of # suppresses substitution - if ( keywords[ strlen( keywords ) -1 ] == '\\' ) - { - // keep characters except backslash - strncat( result, keywords, sizeof( result ) - strlen( result ) - 2 ); - strcat( result, "#" ); - ct++; - } - else - { - strncat( result, keywords, sizeof( result ) - strlen( result ) - 1 ); - } - } - else if ( !strcmp( keywords, "timecode" ) ) - { - // special case: replace #timecode# with current frame timecode - mlt_position frames = mlt_properties_get_position( feed, "position" ); - mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); - char *s = mlt_properties_frames_to_time( properties, frames, mlt_time_smpte_df ); - if ( s ) - strncat( result, s, sizeof( result ) - strlen( result ) - 1 ); - } - else if ( !strcmp( keywords, "frame" ) ) - { - // special case: replace #frame# with current frame number - int pos = mlt_properties_get_int( feed, "position" ); - char s[12]; - snprintf( s, sizeof(s) - 1, "%d", pos ); - s[sizeof( s ) - 1] = '\0'; - strncat( result, s, sizeof( result ) - strlen( result ) - 1 ); - } - else - { - // replace keyword with metadata value - char *metavalue = metadata_value( MLT_FRAME_PROPERTIES( frame ), keywords ); - strncat( result, metavalue ? metavalue : "-", sizeof( result ) - strlen( result ) -1 ); - } - keywords = strtok( NULL, "#" ); - ct++; - } - mlt_properties_set( properties, key, (char*) result ); - } - else mlt_properties_set( properties, key, value ); - } - } - } - } - - // Set the original position on the frame - if ( absolute == 0 ) - mlt_frame_set_position( frame, mlt_properties_get_int( feed, "position" ) - mlt_properties_get_int( feed, "in" ) ); - else - mlt_frame_set_position( frame, mlt_properties_get_int( feed, "position" ) ); - - // Process the filter - mlt_filter_process( requested, frame ); - - // Should be ok... - error = 0; - } - - return error; -} - -void process_queue( mlt_deque data_queue, mlt_frame frame, mlt_filter filter ) -{ - if ( data_queue != NULL ) - { - // Create a new queue for those that we can't handle - mlt_deque temp_queue = mlt_deque_init( ); - - // Iterate through each entry on the queue - while ( mlt_deque_peek_front( data_queue ) != NULL ) - { - // Get the data feed - mlt_properties feed = mlt_deque_pop_front( data_queue ); - - if ( mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "debug" ) != NULL ) - mlt_properties_debug( feed, mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "debug" ), stderr ); - - // Process the data feed... - if ( process_feed( feed, filter, frame ) == 0 ) - mlt_properties_close( feed ); - else - mlt_deque_push_back( temp_queue, feed ); - } - - // Now put the unprocessed feeds back on the stack - while ( mlt_deque_peek_front( temp_queue ) ) - { - // Get the data feed - mlt_properties feed = mlt_deque_pop_front( temp_queue ); - - // Put it back on the data queue - mlt_deque_push_back( data_queue, feed ); - } - - // Close the temporary queue - mlt_deque_close( temp_queue ); - } -} - -/** Get the image. -*/ - -static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) -{ - // Pop the service - mlt_filter filter = mlt_frame_pop_service( frame ); - - // Get the frame properties - mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); - - mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); - - // Track specific - process_queue( mlt_properties_get_data( frame_properties, "data_queue", NULL ), frame, filter ); - - // Global - process_queue( mlt_properties_get_data( frame_properties, "global_queue", NULL ), frame, filter ); - - mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); - - // Need to get the image - return mlt_frame_get_image( frame, image, format, width, height, 1 ); -} - - -/** Filter processing. -*/ - -static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) -{ - // Push the filter - mlt_frame_push_service( frame, filter ); - - // Register the get image method - mlt_frame_push_get_image( frame, filter_get_image ); - - // Return the frame - return frame; -} - -/** Constructor for the filter. -*/ - -mlt_filter filter_data_show_init( mlt_profile profile, mlt_service_type type, const char *id, void *arg ) -{ - // Create the filter - mlt_filter filter = mlt_filter_new( ); - - // Initialise it - if ( filter != NULL ) - { - // Get the properties - mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); - - // Assign the argument (default to titles) - mlt_properties_set( properties, "resource", arg == NULL ? NULL : arg ); - - // Specify the processing method - filter->process = filter_process; - } - - return filter; -} - diff --git a/src/modules/core/filter_data_show.yml b/src/modules/core/filter_data_show.yml deleted file mode 100644 index d899616a1..000000000 --- a/src/modules/core/filter_data_show.yml +++ /dev/null @@ -1,50 +0,0 @@ -schema_version: 0.1 -type: filter -identifier: data_show -title: Template (*deprecated*) -version: 1 -copyright: Meltytech, LLC -creator: Charles Yates -license: LGPLv2.1 -language: en -tags: - - Video -description: Show data based on properties of the producer. -notes: | - The data show filter uses data provided by the data feed filter. - The producer properties must supply: > - * The keyword text to be inserted in the form of: - meta.attr.[keyword].markup=[text to insert] - - * The name of the properties to be used from the feed file in the form of: - meta.attr.[name]=1 - - * The text to be displayed in the form of: - meta.attr.[name].markup=[some text #keyword#] - (Keyword text is enclosed between #s.) - - e.g. - melt file.dv meta.attr.sometext.markup="this is some text" meta.attr.titles=1 meta.attr.titles.markup=#sometext# -filter data_show dynamic=1 - > - Two special keywords exist - * #timecode# shows the frame position as a timecode. - * #frame# shows the frame position as an integer. - e.g. - melt file.dv meta.attr.timecode=1 meta.attr.timecode.markup=#timecode# -attach data_feed:attr_check -attach data_show:custom_file.properties dynamic=1 - (where the file "custom_file" contains a filter definition by the name of "timecode") -parameters: - - identifier: argument - title: Feed Properties File - type: string - required: no - readonly: no - default: data_fx.properties - widget: fileopen - - - identifier: dynamic - title: Dynamic - type: integer - default: 0 - minimum: 0 - maximum: 1 - widget: checkbox diff --git a/src/modules/core/filter_imageconvert.c b/src/modules/core/filter_imageconvert.c index 71a035601..d3ba700bf 100644 --- a/src/modules/core/filter_imageconvert.c +++ b/src/modules/core/filter_imageconvert.c @@ -1,6 +1,6 @@ /* * filter_imageconvert.c -- colorspace and pixel format converter - * Copyright (C) 2009-2014 Meltytech, LLC + * Copyright (C) 2009-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 @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -54,256 +55,410 @@ #define YUV2RGB_601 YUV2RGB_601_UNSCALED #endif -static int convert_yuv422_to_rgb24a( uint8_t *yuv, uint8_t *rgba, uint8_t *alpha, int width, int height ) +static void convert_yuv422_to_rgba( mlt_image src, mlt_image dst ) { - int ret = 0; int yy, uu, vv; int r,g,b; - int total = width * height / 2 + 1; - while ( --total ) + mlt_image_set_values( dst, NULL, mlt_image_rgba, src->width, src->height ); + mlt_image_alloc_data( dst ); + + for ( int line = 0; line < src->height; line++ ) { - yy = yuv[0]; - uu = yuv[1]; - vv = yuv[3]; - YUV2RGB_601( yy, uu, vv, r, g, b ); - rgba[0] = r; - rgba[1] = g; - rgba[2] = b; - rgba[3] = *alpha++; - yy = yuv[2]; - YUV2RGB_601( yy, uu, vv, r, g, b ); - rgba[4] = r; - rgba[5] = g; - rgba[6] = b; - rgba[7] = *alpha++; - yuv += 4; - rgba += 8; + uint8_t* pSrc = src->planes[0] + src->strides[0] * line; + uint8_t* pAlpha = src->planes[3] + src->strides[3] * line; + uint8_t* pDst = dst->planes[0] + dst->strides[0] * line; + int total = src->width / 2 + 1; + + if ( pAlpha ) + while ( --total ) + { + yy = pSrc[0]; + uu = pSrc[1]; + vv = pSrc[3]; + YUV2RGB_601( yy, uu, vv, r, g, b ); + pDst[0] = r; + pDst[1] = g; + pDst[2] = b; + pDst[3] = *pAlpha++; + yy = pSrc[2]; + YUV2RGB_601( yy, uu, vv, r, g, b ); + pDst[4] = r; + pDst[5] = g; + pDst[6] = b; + pDst[7] = *pAlpha++; + pSrc += 4; + pDst += 8; + } + else + while ( --total ) + { + yy = pSrc[0]; + uu = pSrc[1]; + vv = pSrc[3]; + YUV2RGB_601( yy, uu, vv, r, g, b ); + pDst[0] = r; + pDst[1] = g; + pDst[2] = b; + pDst[3] = 0xff; + yy = pSrc[2]; + YUV2RGB_601( yy, uu, vv, r, g, b ); + pDst[4] = r; + pDst[5] = g; + pDst[6] = b; + pDst[7] = 0xff; + pSrc += 4; + pDst += 8; + } } - return ret; } -static int convert_yuv422_to_rgb24( uint8_t *yuv, uint8_t *rgb, uint8_t *alpha, int width, int height ) +static void convert_yuv422_to_rgb( mlt_image src, mlt_image dst ) { - int ret = 0; int yy, uu, vv; int r,g,b; - int total = width * height / 2 + 1; - while ( --total ) + mlt_image_set_values( dst, NULL, mlt_image_rgb, src->width, src->height ); + mlt_image_alloc_data( dst ); + + for ( int line = 0; line < src->height; line++ ) { - yy = yuv[0]; - uu = yuv[1]; - vv = yuv[3]; - YUV2RGB_601( yy, uu, vv, r, g, b ); - rgb[0] = r; - rgb[1] = g; - rgb[2] = b; - yy = yuv[2]; - YUV2RGB_601( yy, uu, vv, r, g, b ); - rgb[3] = r; - rgb[4] = g; - rgb[5] = b; - yuv += 4; - rgb += 6; + uint8_t* pSrc = src->planes[0] + src->strides[0] * line; + uint8_t* pDst = dst->planes[0] + dst->strides[0] * line; + int total = src->width / 2 + 1; + while ( --total ) + { + yy = pSrc[0]; + uu = pSrc[1]; + vv = pSrc[3]; + YUV2RGB_601( yy, uu, vv, r, g, b ); + pDst[0] = r; + pDst[1] = g; + pDst[2] = b; + yy = pSrc[2]; + YUV2RGB_601( yy, uu, vv, r, g, b ); + pDst[3] = r; + pDst[4] = g; + pDst[5] = b; + pSrc += 4; + pDst += 6; + } } - return ret; } -static int convert_rgb24a_to_yuv422( uint8_t *rgba, uint8_t *yuv, uint8_t *alpha, int width, int height ) +static void convert_rgba_to_yuv422( mlt_image src, mlt_image dst ) { - int ret = 0; - int stride = width * 4; int y0, y1, u0, u1, v0, v1; int r, g, b; - uint8_t *s, *d = yuv; - int i, j, n = width / 2 + 1; - if ( alpha ) - for ( i = 0; i < height; i++ ) + mlt_image_set_values( dst, NULL, mlt_image_yuv422, src->width, src->height ); + mlt_image_alloc_data( dst ); + mlt_image_alloc_alpha( dst ); + + for ( int line = 0; line < src->height; line++ ) { - s = rgba + ( stride * i ); - j = n; + uint8_t* pSrc = src->planes[0] + src->strides[0] * line; + uint8_t* pDst = dst->planes[0] + dst->strides[0] * line; + uint8_t* pAlpha = dst->planes[3] + dst->strides[3] * line; + int j = src->width / 2 + 1; while ( --j ) { - r = *s++; - g = *s++; - b = *s++; - *alpha++ = *s++; + r = *pSrc++; + g = *pSrc++; + b = *pSrc++; + *pAlpha++ = *pSrc++; RGB2YUV_601( r, g, b, y0, u0 , v0 ); - r = *s++; - g = *s++; - b = *s++; - *alpha++ = *s++; + r = *pSrc++; + g = *pSrc++; + b = *pSrc++; + *pAlpha++ = *pSrc++; RGB2YUV_601( r, g, b, y1, u1 , v1 ); - *d++ = y0; - *d++ = (u0+u1) >> 1; - *d++ = y1; - *d++ = (v0+v1) >> 1; + *pDst++ = y0; + *pDst++ = (u0+u1) >> 1; + *pDst++ = y1; + *pDst++ = (v0+v1) >> 1; } - if ( width % 2 ) + if ( src->width % 2 ) { - r = *s++; - g = *s++; - b = *s++; - *alpha++ = *s++; + r = *pSrc++; + g = *pSrc++; + b = *pSrc++; + *pAlpha++ = *pSrc++; RGB2YUV_601( r, g, b, y0, u0 , v0 ); - *d++ = y0; - *d++ = u0; + *pDst++ = y0; + *pDst++ = u0; } } - else - for ( i = 0; i < height; i++ ) +} + +static void convert_rgb_to_yuv422( mlt_image src, mlt_image dst ) +{ + int y0, y1, u0, u1, v0, v1; + int r, g, b; + + mlt_image_set_values( dst, NULL, mlt_image_yuv422, src->width, src->height ); + mlt_image_alloc_data( dst ); + + for ( int line = 0; line < src->height; line++ ) { - s = rgba + ( stride * i ); - j = n; + uint8_t* pSrc = src->planes[0] + src->strides[0] * line; + uint8_t* pDst = dst->planes[0] + dst->strides[0] * line; + int j = src->width / 2 + 1; while ( --j ) { - r = *s++; - g = *s++; - b = *s++; - s++; + r = *pSrc++; + g = *pSrc++; + b = *pSrc++; RGB2YUV_601( r, g, b, y0, u0 , v0 ); - r = *s++; - g = *s++; - b = *s++; - s++; + r = *pSrc++; + g = *pSrc++; + b = *pSrc++; RGB2YUV_601( r, g, b, y1, u1 , v1 ); - *d++ = y0; - *d++ = (u0+u1) >> 1; - *d++ = y1; - *d++ = (v0+v1) >> 1; + *pDst++ = y0; + *pDst++ = (u0+u1) >> 1; + *pDst++ = y1; + *pDst++ = (v0+v1) >> 1; } - if ( width % 2 ) + if ( src->width % 2 ) { - r = *s++; - g = *s++; - b = *s++; - s++; + r = *pSrc++; + g = *pSrc++; + b = *pSrc++; RGB2YUV_601( r, g, b, y0, u0 , v0 ); - *d++ = y0; - *d++ = u0; + *pDst++ = y0; + *pDst++ = u0; } } - - return ret; } -static int convert_rgb24_to_yuv422( uint8_t *rgb, uint8_t *yuv, uint8_t *alpha, int width, int height ) +static void convert_yuv420p_to_yuv422( mlt_image src, mlt_image dst ) { - int ret = 0; - int stride = width * 3; - int y0, y1, u0, u1, v0, v1; - int r, g, b; - uint8_t *s, *d = yuv; - int i, j, n = width / 2 + 1; + mlt_image_set_values( dst, NULL, mlt_image_yuv422, src->width, src->height ); + mlt_image_alloc_data( dst ); - for ( i = 0; i < height; i++ ) + for ( int line = 0; line < src->height; line++ ) { - s = rgb + ( stride * i ); - j = n; + uint8_t* pSrcY = src->planes[0] + src->strides[0] * line; + uint8_t* pSrcU = src->planes[1] + src->strides[1] * line / 2; + uint8_t* pSrcV = src->planes[2] + src->strides[2] * line / 2; + uint8_t* pDst = dst->planes[0] + dst->strides[0] * line; + int j = src->width / 2 + 1; while ( --j ) { - r = *s++; - g = *s++; - b = *s++; - RGB2YUV_601( r, g, b, y0, u0 , v0 ); - r = *s++; - g = *s++; - b = *s++; - RGB2YUV_601( r, g, b, y1, u1 , v1 ); - *d++ = y0; - *d++ = (u0+u1) >> 1; - *d++ = y1; - *d++ = (v0+v1) >> 1; + *pDst++ = *pSrcY++; + *pDst++ = *pSrcU++; + *pDst++ = *pSrcY++; + *pDst++ = *pSrcV++; } - if ( width % 2 ) + } +} + +static void convert_yuv420p_to_rgb( mlt_image src, mlt_image dst ) +{ + int yy, uu, vv; + int r,g,b; + + mlt_image_set_values( dst, NULL, mlt_image_rgb, src->width, src->height ); + mlt_image_alloc_data( dst ); + + for ( int line = 0; line < src->height; line++ ) + { + uint8_t* pSrcY = src->planes[0] + src->strides[0] * line; + uint8_t* pSrcU = src->planes[1] + src->strides[1] * line / 2; + uint8_t* pSrcV = src->planes[2] + src->strides[2] * line / 2; + uint8_t* pDst = dst->planes[0] + dst->strides[0] * line; + int total = src->width / 2 + 1; + while ( --total ) { - r = *s++; - g = *s++; - b = *s++; - RGB2YUV_601( r, g, b, y0, u0 , v0 ); - *d++ = y0; - *d++ = u0; + yy = *pSrcY++; + uu = *pSrcU++; + vv = *pSrcV++; + YUV2RGB_601( yy, uu, vv, r, g, b ); + pDst[0] = r; + pDst[1] = g; + pDst[2] = b; + yy = *pSrcY++; + YUV2RGB_601( yy, uu, vv, r, g, b ); + pDst[3] = r; + pDst[4] = g; + pDst[5] = b; + pDst += 6; } } - return ret; } -static int convert_yuv420p_to_yuv422( uint8_t *yuv420p, uint8_t *yuv, uint8_t *alpha, int width, int height ) +static void convert_yuv420p_to_rgba( mlt_image src, mlt_image dst ) { - int ret = 0; - int i, j; - int half = width >> 1; - uint8_t *Y = yuv420p; - uint8_t *U = Y + width * height; - uint8_t *V = U + width * height / 4; - uint8_t *d = yuv; - - for ( i = 0; i < height; i++ ) + int yy, uu, vv; + int r,g,b; + + mlt_image_set_values( dst, NULL, mlt_image_rgba, src->width, src->height ); + mlt_image_alloc_data( dst ); + + for ( int line = 0; line < src->height; line++ ) { - uint8_t *u = U + ( i / 2 ) * ( half ); - uint8_t *v = V + ( i / 2 ) * ( half ); + uint8_t* pSrcY = src->planes[0] + src->strides[0] * line; + uint8_t* pSrcU = src->planes[1] + src->strides[1] * line / 2; + uint8_t* pSrcV = src->planes[2] + src->strides[2] * line / 2; + uint8_t* pSrcA = src->planes[3] + src->strides[3] * line; + uint8_t* pDst = dst->planes[0] + dst->strides[0] * line; + int total = src->width / 2 + 1; + if ( pSrcA ) + while ( --total ) + { + yy = *pSrcY++; + uu = *pSrcU++; + vv = *pSrcV++; + YUV2RGB_601( yy, uu, vv, r, g, b ); + pDst[0] = r; + pDst[1] = g; + pDst[2] = b; + pDst[3] = *pSrcA++; + yy = *pSrcY++; + YUV2RGB_601( yy, uu, vv, r, g, b ); + pDst[4] = r; + pDst[5] = g; + pDst[6] = b; + pDst[7] = *pSrcA++; + pDst += 8; + } + else + while ( --total ) + { + yy = *pSrcY++; + uu = *pSrcU++; + vv = *pSrcV++; + YUV2RGB_601( yy, uu, vv, r, g, b ); + pDst[0] = r; + pDst[1] = g; + pDst[2] = b; + pDst[3] = 0xff; + yy = *pSrcY++; + YUV2RGB_601( yy, uu, vv, r, g, b ); + pDst[4] = r; + pDst[5] = g; + pDst[6] = b; + pDst[7] = 0xff; + pDst += 8; + } + } +} - j = half + 1; - while ( --j ) +static void convert_yuv422_to_yuv420p( mlt_image src, mlt_image dst ) +{ + int lines = src->height; + int pixels = src->width; + + mlt_image_set_values( dst, NULL, mlt_image_yuv420p, src->width, src->height ); + mlt_image_alloc_data( dst ); + + // Y + for ( int line = 0; line < lines; line++ ) + { + uint8_t* pSrc = src->planes[0] + src->strides[0] * line; + uint8_t* pDst = dst->planes[0] + dst->strides[0] * line; + for ( int pixel = 0; pixel < pixels; pixel++ ) + { + *pDst++ = *pSrc; + pSrc += 2; + } + } + + lines = src->height / 2; + pixels = src->width / 2; + + // U + for ( int line = 0; line < lines; line++ ) + { + uint8_t* pSrc = src->planes[0] + src->strides[0] * line * 2 + 1; + uint8_t* pDst = dst->planes[1] + dst->strides[1] * line; + for ( int pixel = 0; pixel < pixels; pixel++ ) { - *d ++ = *Y ++; - *d ++ = *u ++; - *d ++ = *Y ++; - *d ++ = *v ++; + *pDst++ = *pSrc; + pSrc += 4; + } + } + + // V + for ( int line = 0; line < lines; line++ ) + { + uint8_t* pSrc = src->planes[0] + src->strides[0] * line * 2 + 3; + uint8_t* pDst = dst->planes[2] + dst->strides[2] * line; + for ( int pixel = 0; pixel < pixels; pixel++ ) + { + *pDst++ = *pSrc; + pSrc += 4; } } - return ret; } -static int convert_rgb24_to_rgb24a( uint8_t *rgb, uint8_t *rgba, uint8_t *alpha, int width, int height ) +static void convert_rgb_to_rgba( mlt_image src, mlt_image dst ) { - uint8_t *s = rgb; - uint8_t *d = rgba; - int total = width * height + 1; + mlt_image_set_values( dst, NULL, mlt_image_rgba, src->width, src->height ); + mlt_image_alloc_data( dst ); - while ( --total ) + for ( int line = 0; line < src->height; line++ ) { - *d++ = s[0]; - *d++ = s[1]; - *d++ = s[2]; - *d++ = 0xff; - s += 3; + uint8_t* pSrc = src->planes[0] + src->strides[0] * line; + uint8_t* pAlpha = src->planes[3] + src->strides[3] * line; + uint8_t* pDst = dst->planes[0] + dst->strides[0] * line; + int total = src->width + 1; + if ( pAlpha ) + while ( --total ) + { + *pDst++ = pSrc[0]; + *pDst++ = pSrc[1]; + *pDst++ = pSrc[2]; + *pDst++ = *pAlpha++; + pSrc += 3; + } + else + while ( --total ) + { + *pDst++ = pSrc[0]; + *pDst++ = pSrc[1]; + *pDst++ = pSrc[2]; + *pDst++ = 0xff; + pSrc += 3; + } } - return 0; } -static int convert_rgb24a_to_rgb24( uint8_t *rgba, uint8_t *rgb, uint8_t *alpha, int width, int height ) +static void convert_rgba_to_rgb( mlt_image src, mlt_image dst ) { - uint8_t *s = rgba; - uint8_t *d = rgb; - int total = width * height + 1; + mlt_image_set_values( dst, NULL, mlt_image_rgb, src->width, src->height ); + mlt_image_alloc_data( dst ); + mlt_image_alloc_alpha( dst ); - while ( --total ) + for ( int line = 0; line < src->height; line++ ) { - *d++ = s[0]; - *d++ = s[1]; - *d++ = s[2]; - *alpha++ = s[3]; - s += 4; + uint8_t* pSrc = src->planes[0] + src->strides[0] * line; + uint8_t* pDst = dst->planes[0] + dst->strides[0] * line; + uint8_t* pAlpha = dst->planes[3] + dst->strides[3] * line; + int total = src->width + 1; + while ( --total ) + { + *pDst++ = pSrc[0]; + *pDst++ = pSrc[1]; + *pDst++ = pSrc[2]; + *pAlpha++ = pSrc[3]; + pSrc += 4; + } } - return 0; } -typedef int ( *conversion_function )( uint8_t *yuv, uint8_t *rgba, uint8_t *alpha, int width, int height ); +typedef void ( *conversion_function )( mlt_image src, mlt_image dst ); static conversion_function conversion_matrix[ mlt_image_invalid - 1 ][ mlt_image_invalid - 1 ] = { - { NULL, convert_rgb24_to_rgb24a, convert_rgb24_to_yuv422, NULL, convert_rgb24_to_rgb24a, NULL }, - { convert_rgb24a_to_rgb24, NULL, convert_rgb24a_to_yuv422, NULL, NULL, NULL }, - { convert_yuv422_to_rgb24, convert_yuv422_to_rgb24a, NULL, NULL, convert_yuv422_to_rgb24a, NULL }, - { NULL, NULL, convert_yuv420p_to_yuv422, NULL, NULL, NULL }, - { convert_rgb24a_to_rgb24, NULL, convert_rgb24a_to_yuv422, NULL, NULL, NULL }, - { NULL, NULL, NULL, NULL, NULL, NULL }, + { NULL, convert_rgb_to_rgba, convert_rgb_to_yuv422, NULL, NULL, NULL, NULL }, + { convert_rgba_to_rgb, NULL, convert_rgba_to_yuv422, NULL, NULL, NULL, NULL }, + { convert_yuv422_to_rgb, convert_yuv422_to_rgba, NULL, convert_yuv422_to_yuv420p, NULL, NULL, NULL }, + { convert_yuv420p_to_rgb, convert_yuv420p_to_rgba, convert_yuv420p_to_yuv422, NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL, NULL, NULL }, }; -static uint8_t bpp_table[4] = { 3, 4, 2, 0 }; - static int convert_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, mlt_image_format requested_format ) { int error = 0; @@ -320,37 +475,34 @@ static int convert_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *f width, height ); if ( converter ) { - int size = width * height * bpp_table[ requested_format - 1 ]; - int alpha_size = width * height; - uint8_t *image = mlt_pool_alloc( size ); - uint8_t *alpha = ( *format == mlt_image_rgb24a || - *format == mlt_image_opengl ) - ? mlt_pool_alloc( width * height ) : NULL; - if ( requested_format == mlt_image_rgb24a || requested_format == mlt_image_opengl ) + struct mlt_image_s src; + struct mlt_image_s dst; + mlt_image_set_values( &src, *buffer, *format, width, height ); + if ( requested_format == mlt_image_rgba && mlt_frame_get_alpha( frame ) ) { - if ( alpha ) - mlt_pool_release( alpha ); - alpha = mlt_frame_get_alpha_mask( frame ); - mlt_properties_get_data( properties, "alpha", &alpha_size ); + // imageconvert leaves the alpha buffer alone except in the case of rgba. + // For rgba input, an alpha buffer will be created and added to the frame. + // For rgba output, the alpha buffer will be copied to the rgba and the buffer is removed from the frame. + src.planes[3] = mlt_frame_get_alpha( frame ); + src.strides[3] = src.width; } - - if ( !( error = converter( *buffer, image, alpha, width, height ) ) ) + converter( &src, &dst ); + mlt_frame_set_image( frame, dst.data, 0, dst.release_data ); + if ( requested_format == mlt_image_rgba ) { - mlt_frame_set_image( frame, image, size, mlt_pool_release ); - if ( alpha && ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) ) - mlt_frame_set_alpha( frame, alpha, alpha_size, mlt_pool_release ); - *buffer = image; - *format = requested_format; + // Clear the alpha buffer on the frame + mlt_frame_set_alpha( frame, NULL, 0, NULL ); } - else + else if ( dst.alpha ) { - mlt_pool_release( image ); - if ( alpha ) - mlt_pool_release( alpha ); + mlt_frame_set_alpha( frame, dst.alpha, 0, dst.release_alpha ); } + *buffer = dst.data; + *format = dst.format; } else { + mlt_log_error( NULL, "imageconvert: no conversion from %s to %s\n", mlt_image_format_name(*format), mlt_image_format_name(requested_format)); error = 1; } } diff --git a/src/modules/core/filter_mask_apply.c b/src/modules/core/filter_mask_apply.c index 89953e467..90e6413b0 100644 --- a/src/modules/core/filter_mask_apply.c +++ b/src/modules/core/filter_mask_apply.c @@ -106,7 +106,7 @@ mlt_filter filter_mask_apply_init(mlt_profile profile, mlt_service_type type, co mlt_filter filter = mlt_filter_new( ); if (filter) { mlt_properties_set(MLT_FILTER_PROPERTIES(filter), "transition", arg? arg : "frei0r.composition"); - mlt_properties_set(MLT_FILTER_PROPERTIES(filter), "mlt_image_format", "rgb24a"); + mlt_properties_set(MLT_FILTER_PROPERTIES(filter), "mlt_image_format", "rgba"); filter->process = process; } return filter; diff --git a/src/modules/core/filter_mirror.c b/src/modules/core/filter_mirror.c index 04b94a414..90a534d5e 100644 --- a/src/modules/core/filter_mirror.c +++ b/src/modules/core/filter_mirror.c @@ -1,6 +1,6 @@ /* * filter_mirror.c -- mirror filter - * Copyright (C) 2003-2014 Meltytech, LLC + * Copyright (C) 2003-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 @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -29,6 +30,9 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { + struct mlt_image_s img; + int i; + // Pop the mirror filter from the stack mlt_filter filter = mlt_frame_pop_service( frame ); @@ -45,29 +49,23 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format = mlt_image_yuv422; int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); - // Get the alpha - uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); - // If we have an image of the right colour space - if ( error == 0 ) + if ( error == 0 && *format == mlt_image_yuv422 ) { - // We'll KISS here - int hh = *height / 2; + 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" ) ) { - uint8_t *p = NULL; - uint8_t *q = NULL; - uint8_t *a = NULL; - uint8_t *b = NULL; - int i; - int uneven_w = ( *width % 2 ) * 2; - for ( i = 0; i < *height; i ++ ) + int uneven_w = ( img.width % 2 ) * 2; + for ( i = 0; i < img.height; i ++ ) { - p = ( uint8_t * )*image + i * *width * 2; - q = p + *width * 2; - a = alpha + i * *width; - b = a + *width - 1; + uint8_t* p = img.planes[0] + img.strides[0] * i; + uint8_t* q = p + img.width * 2; if ( !reverse ) { while ( p < q ) @@ -77,8 +75,6 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *p ++ = *( q - 4 ); *p ++ = *( q - 1 - uneven_w ); q -= 4; - *a ++ = *b --; - *a ++ = *b --; } } else @@ -90,34 +86,48 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *( q - 4 ) = *p ++; *( q - 1 - uneven_w ) = *p ++; q -= 4; - *b -- = *a ++; - *b -- = *a ++; } } } + if ( img.planes[3] ) + { + for ( i = 0; i < img.height; i ++ ) + { + uint8_t* a = img.planes[3] + img.strides[3] * i; + uint8_t* b = a + img.width - 1; + if ( !reverse ) + { + while ( a < b ) + { + *a ++ = *b --; + *a ++ = *b --; + } + } + else + { + while ( a < b ) + { + *b -- = *a ++; + *b -- = *a ++; + } + } + } + } + } else if ( !strcmp( mirror, "vertical" ) ) { - uint16_t *end = ( uint16_t *)*image + *width * *height; - uint16_t *p = NULL; - uint16_t *q = NULL; - uint8_t *a = NULL; - uint8_t *b = NULL; - int i; - int j; + int hh = img.height / 2; for ( i = 0; i < hh; i ++ ) { - p = ( uint16_t * )*image + i * *width; - q = end - ( i + 1 ) * *width; - j = *width; - a = alpha + i * *width; - b = alpha + ( *height - i - 1 ) * *width; + 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 -- ) { *p ++ = *q ++; - *a ++ = *b ++; } } else @@ -125,28 +135,30 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format while ( j -- ) { *q ++ = *p ++; - *b ++ = *a ++; } } } + if ( img.planes[3] ) + { + 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 ) + while ( j -- ) + *a ++ = *b ++; + else + while ( j -- ) + *b ++ = *a ++; + } } else if ( !strcmp( mirror, "diagonal" ) ) { - uint8_t *end = ( uint8_t *)*image + *width * *height * 2; - uint8_t *p = NULL; - uint8_t *q = NULL; - uint8_t *a = NULL; - uint8_t *b = NULL; - int i; - int j; - int uneven_w = ( *width % 2 ) * 2; - for ( i = 0; i < *height; i ++ ) + int uneven_w = ( img.width % 2 ) * 2; + for ( i = 0; i < img.height; i ++ ) { - p = ( uint8_t * )*image + i * *width * 2; - q = end - i * *width * 2; - j = ( ( *width * ( *height - i ) ) / *height ) / 2; - a = alpha + i * *width; - b = alpha + ( *height - i - 1 ) * *width; + 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 -- ) @@ -156,8 +168,6 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *p ++ = *( q - 4 ); *p ++ = *( q - 1 - uneven_w ); q -= 4; - *a ++ = *b --; - *a ++ = *b --; } } else @@ -169,29 +179,34 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *( q - 4 ) = *p ++; *( q - 1 - uneven_w ) = *p ++; q -= 4; - *b -- = *a ++; - *b -- = *a ++; } } } + if ( img.planes[3] ) + { + int i; + for ( i = 0; i < img.height; i ++ ) + { + 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 ++; + } + } } else if ( !strcmp( mirror, "xdiagonal" ) ) { - uint8_t *end = ( uint8_t *)*image + *width * *height * 2; - uint8_t *p = NULL; - uint8_t *q = NULL; - int i; - int j; - uint8_t *a = NULL; - uint8_t *b = NULL; - int uneven_w = ( *width % 2 ) * 2; - for ( i = 0; i < *height; i ++ ) + int uneven_w = ( img.width % 2 ) * 2; + for ( i = 0; i < img.height; i ++ ) { - p = ( uint8_t * )*image + ( i + 1 ) * *width * 2; - q = end - ( i + 1 ) * *width * 2; - j = ( ( *width * ( *height - i ) ) / *height ) / 2; - a = alpha + ( i + 1 ) * *width - 1; - b = alpha + ( *height - i - 1 ) * *width; + 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 ) { while ( j -- ) @@ -201,8 +216,6 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *q ++ = *( p - 4 ); *q ++ = *( p - 1 - uneven_w ); p -= 4; - *b ++ = *a --; - *b ++ = *a --; } } else @@ -214,28 +227,34 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *( p - 4 ) = *q ++; *( p - 1 - uneven_w ) = *q ++; p -= 4; - *a -- = *b ++; - *a -- = *b ++; } } } + if ( img.planes[3] ) + { + int i; + for ( i = 0; i < img.height; i ++ ) + { + 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 ++; + } + } } else if ( !strcmp( mirror, "flip" ) ) { uint8_t t[ 4 ]; - uint8_t *p = NULL; - uint8_t *q = NULL; - int i; - uint8_t *a = NULL; - uint8_t *b = NULL; - uint8_t c; - int uneven_w = ( *width % 2 ) * 2; - for ( i = 0; i < *height; i ++ ) + int uneven_w = ( img.width % 2 ) * 2; + for ( i = 0; i < img.height; i ++ ) { - p = ( uint8_t * )*image + i * *width * 2; - q = p + *width * 2; - a = alpha + i * *width; - b = a + *width - 1; + uint8_t* p = img.planes[0] + (img.strides[0] * i); + uint8_t* q = p + *width * 2; while ( p < q ) { t[ 0 ] = p[ 0 ]; @@ -250,41 +269,53 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *( -- q ) = t[ 0 ]; *( -- q ) = t[ 1 ]; *( -- q ) = t[ 2 ]; - c = *a; - *a ++ = *b; - *b -- = c; - c = *a; - *a ++ = *b; - *b -- = c; + } + } + if ( img.planes[3] ) + { + 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; + } } } } else if ( !strcmp( mirror, "flop" ) ) { - uint16_t *end = ( uint16_t *)*image + *width * *height; - uint16_t *p = NULL; - uint16_t *q = NULL; uint16_t t; - uint8_t *a = NULL; - uint8_t *b = NULL; - uint8_t c; - int i; - int j; + int hh = *height / 2; for ( i = 0; i < hh; i ++ ) { - p = ( uint16_t * )*image + i * *width; - q = end - ( i + 1 ) * *width; - a = alpha + i * *width; - b = alpha + ( *height - i - 1 ) * *width; - j = *width; + 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; - c = *a; - *a ++ = *b; - *b ++ = c; + } + } + if ( img.planes[3] ) + { + 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; + } } } } diff --git a/src/modules/core/filter_region.c b/src/modules/core/filter_region.c deleted file mode 100644 index a63f15599..000000000 --- a/src/modules/core/filter_region.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * filter_region.c -- region filter - * Copyright (C) 2003-2014 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 "transition_region.h" - -#include -#include - -#include -#include -#include - -/** Filter processing. -*/ - -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 ); - - // Get the properties of the filter - mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); - - mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); - - // Get the region transition - mlt_transition transition = mlt_properties_get_data( properties, "_transition", NULL ); - - // Create the transition if not available - if ( transition == NULL ) - { - // Create the transition - mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); - transition = mlt_factory_transition( profile, "region", NULL ); - - // Register with the filter - mlt_properties_set_data( properties, "_transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL ); - - // Pass a reference to this filter down - mlt_properties_set_data( MLT_TRANSITION_PROPERTIES( transition ), "_region_filter", filter, 0, NULL, NULL ); - } - - mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); - - // Pass all properties down - mlt_properties_inherit( MLT_TRANSITION_PROPERTIES( transition ), properties ); - - // Make the frame's position relative to this filter's in point - mlt_frame_set_position( frame, mlt_filter_get_position( filter, frame ) ); - - // Process the frame - mlt_transition_process( transition, frame, NULL ); - - int result = mlt_frame_get_image( frame, image, format, width, height, writable ); - - // Restore the frame's position. - mlt_frame_set_position( frame, mlt_frame_original_position( frame ) ); - - return result; -} - -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_region_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - // Create a new filter - mlt_filter filter = mlt_filter_new( ); - - // Further initialisation - if ( filter != NULL ) - { - // Get the properties from the filter - mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); - - // Assign the filter process method - filter->process = filter_process; - - // Resource defines the shape of the region - mlt_properties_set( properties, "resource", arg == NULL ? "rectangle" : arg ); - - // Ensure that attached filters are handled privately - mlt_properties_set_int( properties, "_filter_private", 1 ); - } - - // Return the filter - return filter; -} - diff --git a/src/modules/core/filter_region.yml b/src/modules/core/filter_region.yml deleted file mode 100644 index fb12c560f..000000000 --- a/src/modules/core/filter_region.yml +++ /dev/null @@ -1,29 +0,0 @@ -schema_version: 0.1 -type: filter -identifier: region -title: Regionalize (*deprecated*) -version: 1 -copyright: Meltytech, LLC -creator: Charles Yates -license: LGPLv2.1 -language: en -tags: - - Video -description: > - Apply one or more filters to a region of the video image. The region can be - shaped as well using the alpha channel of another producer. -bugs: - - Circle is unpredictable in the absence of the librsvg pixbuf loader. -parameters: - - identifier: argument - title: File - type: string - description: > - A file whose alpha channel will "shape" the region. The string "circle" - is a shortcut but it requires pixbuf with the librsvg loader. The circle - is automatically stretched to the region to create an ellipse. - - identifier: region.* - title: Region - description: > - Properties may be set on the encapsulated region transition. See "region" - transition for details. diff --git a/src/modules/core/filter_rescale.c b/src/modules/core/filter_rescale.c index 92f512f41..cb1722fbc 100644 --- a/src/modules/core/filter_rescale.c +++ b/src/modules/core/filter_rescale.c @@ -229,14 +229,19 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format iwidth, iheight, owidth, oheight, mlt_image_format_name( *format ), interps ); // If valid colorspace - if ( *format == mlt_image_yuv422 || *format == mlt_image_rgb24 || - *format == mlt_image_rgb24a || *format == mlt_image_opengl ) + if ( *format == mlt_image_yuv422 || *format == mlt_image_rgb || + *format == mlt_image_rgba ) { // Call the virtual function scaler_method( frame, image, format, iwidth, iheight, owidth, oheight ); *width = owidth; *height = oheight; } + else + { + *width = iwidth; + *height = iheight; + } // Scale the alpha channel only if exists and not correct size int alpha_size = 0; mlt_properties_get_data( properties, "alpha", &alpha_size ); diff --git a/src/modules/core/filter_resize.c b/src/modules/core/filter_resize.c index e926e74ad..236651cdc 100644 --- a/src/modules/core/filter_resize.c +++ b/src/modules/core/filter_resize.c @@ -85,7 +85,7 @@ static void resize_image( uint8_t *output, int owidth, int oheight, uint8_t *inp return; } - if ( format == mlt_image_rgb24a ) + if ( format == mlt_image_rgba ) { memset(p, 0, size * bpp); if (alpha_value != 0) { @@ -160,7 +160,7 @@ static uint8_t *frame_resize_image( mlt_frame frame, int owidth, int oheight, ml mlt_frame_set_image( frame, output, owidth * ( oheight + 1 ) * bpp, mlt_pool_release ); // We should resize the alpha too - if ( format != mlt_image_rgb24a && alpha && alpha_size >= iwidth * iheight ) + if ( format != mlt_image_rgba && alpha && alpha_size >= iwidth * iheight ) { alpha = resize_alpha( alpha, owidth, oheight, iwidth, iheight, alpha_value ); if ( alpha ) @@ -215,7 +215,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format // 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_rgb24a; + *format = mlt_image_rgba; // Hmmm... char *rescale = mlt_properties_get( properties, "rescale.interp" ); @@ -284,6 +284,11 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format { *image = frame_resize_image( frame, *width, *height, *format ); } + else + { + *width = owidth; + *height = oheight; + } return error; } diff --git a/src/modules/core/filter_watermark.c b/src/modules/core/filter_watermark.c index 270e30a9e..77c758cda 100644 --- a/src/modules/core/filter_watermark.c +++ b/src/modules/core/filter_watermark.c @@ -195,9 +195,10 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format mlt_properties_set( b_props, "rescale.interp", 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_mask( b_frame ); + alpha = mlt_frame_get_alpha( b_frame ); mlt_frame_set_image( frame, *image, *width * *height * 2, NULL ); - mlt_frame_set_alpha( frame, alpha, *width * *height, NULL ); + if ( alpha ) + mlt_frame_set_alpha( frame, alpha, *width * *height, NULL ); mlt_properties_set_int( a_props, "width", *width ); mlt_properties_set_int( a_props, "height", *height ); mlt_properties_set_int( a_props, "progressive", 1 ); diff --git a/src/modules/core/link_timeremap.c b/src/modules/core/link_timeremap.c new file mode 100644 index 000000000..a5c0fa257 --- /dev/null +++ b/src/modules/core/link_timeremap.c @@ -0,0 +1,536 @@ +/* + * link_timeremap.c + * Copyright (C) 2020 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 + +#include +#include +#include +#include + +// Private Types +typedef struct +{ + mlt_frame prev_frame; + mlt_filter resample_filter; + mlt_filter pitch_filter; +} private_data; + +static void link_configure( mlt_link self, mlt_profile chain_profile ) +{ + // Timeremap must always work with the same profile as the chain so that + // animation, in and out will work. + mlt_service_set_profile( MLT_LINK_SERVICE( self ), chain_profile ); +} + +static int link_get_audio( mlt_frame frame, void** audio, mlt_audio_format* format, int* frequency, int* channels, int* samples ) +{ + int requested_frequency = *frequency; + int requested_samples = *samples; + mlt_link self = (mlt_link)mlt_frame_pop_audio( frame ); + private_data* pdata = (private_data*)self->child; + mlt_properties unique_properties = mlt_frame_get_unique_properties( frame, MLT_LINK_SERVICE(self) ); + if ( !unique_properties ) + { + return 1; + } + double source_time = mlt_properties_get_double( unique_properties, "source_time" ); + double source_duration = mlt_properties_get_double( unique_properties, "source_duration" ); + double source_fps = mlt_properties_get_double( unique_properties, "source_fps" ); + double source_speed = mlt_properties_get_double( unique_properties, "source_speed" ); + source_speed = fabs( source_speed ); + double link_fps = mlt_producer_get_fps( MLT_LINK_PRODUCER( self ) ); + + // Validate the request + *channels = *channels <= 0 ? 2 : *channels; + int src_frequency = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "audio_frequency" ); + if ( src_frequency > 0 ) + { + *frequency = src_frequency; + } + else if ( *frequency <= 0 ) + { + *frequency = 48000; + } + + if ( source_speed < 0.1 || source_speed > 10 ) + { + // Return silent samples for speeds less than 0.1 or > 10 + mlt_position position = mlt_frame_original_position( frame ); + *samples = mlt_audio_calculate_frame_samples( link_fps, *frequency, position ); + int size = mlt_audio_format_size( *format, *samples, *channels ); + *audio = mlt_pool_alloc( size ); + memset( *audio, 0, size ); + mlt_frame_set_audio( frame, *audio, *format, size, mlt_pool_release ); + return 0; + } + + // Calculate the samples to get from the input frames + int link_sample_count = mlt_audio_calculate_frame_samples( link_fps, *frequency, mlt_frame_get_position( frame ) ); + int sample_count = lrint( (double)link_sample_count * source_speed ); + mlt_position in_frame_pos = floor( source_time * source_fps ); + int64_t first_out_sample = llrint(source_time * (double)*frequency); + + // Attempt to maintain sample continuity with the previous frame + static const int64_t SAMPLE_CONTINUITY_ERROR_MARGIN = 4; + int64_t continuity_sample = mlt_properties_get_int64( MLT_LINK_PROPERTIES( self ), "_continuity_sample" ); + int64_t continuity_delta = continuity_sample - first_out_sample; + if ( source_duration > 0.0 && continuity_delta != 0 ) + { + // Forward: Continue from where the previous frame left off if within the margin of error + if ( continuity_delta > -SAMPLE_CONTINUITY_ERROR_MARGIN && continuity_delta < SAMPLE_CONTINUITY_ERROR_MARGIN ) + { + sample_count = sample_count - continuity_delta; + first_out_sample = continuity_sample; + mlt_log_debug( MLT_LINK_SERVICE(self), "Maintain Forward Continuity: %d\n", (int)continuity_delta ); + } + } + else if ( source_duration < 0.0 && continuity_delta != sample_count ) + { + // Reverse: End where the previous frame left off if within the margin of error + continuity_delta -= sample_count; + if ( continuity_delta > -SAMPLE_CONTINUITY_ERROR_MARGIN && continuity_delta < SAMPLE_CONTINUITY_ERROR_MARGIN ) + { + sample_count = sample_count + continuity_delta; + mlt_log_debug( MLT_LINK_SERVICE(self), "Maintain Reverse Continuity: %d\n", (int)continuity_delta ); + } + } + + int64_t first_in_sample = mlt_audio_calculate_samples_to_position( source_fps, *frequency, in_frame_pos ); + int samples_to_skip = first_out_sample - first_in_sample; + if ( samples_to_skip < 0 ) + { + mlt_log_error( MLT_LINK_SERVICE(self), "Audio too late: %d\t%d\n", (int)first_out_sample, (int)first_in_sample ); + samples_to_skip = 0; + } + + // Allocate the out buffer + struct mlt_audio_s out; + mlt_audio_set_values( &out, NULL, *frequency, *format, sample_count, *channels ); + mlt_audio_alloc_data( &out ); + + // Copy audio from the input frames to the output buffer + int samples_copied = 0; + int samples_needed = sample_count; + + while ( samples_needed > 0 ) + { + char key[19]; + sprintf( key, "%d", in_frame_pos ); + mlt_frame src_frame = (mlt_frame)mlt_properties_get_data( unique_properties, key, NULL ); + if ( !src_frame ) + { + mlt_log_error( MLT_LINK_SERVICE(self), "Frame not found: %d\n", in_frame_pos ); + break; + } + + int in_samples = mlt_audio_calculate_frame_samples( source_fps, *frequency, in_frame_pos ); + struct mlt_audio_s in; + mlt_audio_set_values( &in, NULL, *frequency, *format, in_samples, *channels ); + + int error = mlt_frame_get_audio( src_frame, &in.data, &in.format, &in.frequency, &in.channels, &in.samples ); + if ( error ) + { + mlt_log_error( MLT_LINK_SERVICE(self), "No audio: %d\n", in_frame_pos ); + break; + } + + int samples_to_copy = in.samples - samples_to_skip; + if ( samples_to_copy > samples_needed ) + { + samples_to_copy = samples_needed; + } + mlt_log_debug( MLT_LINK_SERVICE(self), "Copy: %d\t%d\t%d\t%d\n", samples_to_skip, samples_to_skip + samples_to_copy -1, samples_to_copy, in.samples ); + + if ( samples_to_copy > 0 ) + { + mlt_audio_copy( &out, &in, samples_to_copy, samples_to_skip, samples_copied ); + samples_copied += samples_to_copy; + samples_needed -= samples_to_copy; + } + + samples_to_skip = 0; + in_frame_pos++; + } + + if ( samples_copied != sample_count ) + { + mlt_log_error( MLT_LINK_SERVICE(self), "Sample under run: %d\t%d\n", samples_copied, sample_count ); + mlt_audio_shrink( &out , samples_copied ); + } + + if ( source_duration < 0.0 ) + { + // Going backwards + mlt_audio_reverse( &out ); + mlt_properties_set_int64( MLT_LINK_PROPERTIES( self ), "_continuity_sample", first_out_sample ); + } + else + { + mlt_properties_set_int64( MLT_LINK_PROPERTIES( self ), "_continuity_sample", first_out_sample + sample_count ); + } + + int in_frequency = *frequency; + out.frequency = lrint( (double)out.frequency * (double)sample_count / (double)link_sample_count ); + mlt_frame_set_audio( frame, out.data, out.format, 0, out.release_data ); + mlt_audio_get_values( &out, audio, frequency, format, samples, channels ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "audio_frequency", *frequency ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "audio_channels", *channels ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "audio_samples", *samples ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "audio_format", *format ); + + // Apply pitch compensation if requested + int pitch_compensate = mlt_properties_get_int( MLT_LINK_PROPERTIES( self ), "pitch" ); + if ( pitch_compensate ) + { + if ( !pdata->pitch_filter ) + { + pdata->pitch_filter = mlt_factory_filter( mlt_service_profile( MLT_LINK_SERVICE( self ) ), "rbpitch", NULL ); + } + if ( pdata->pitch_filter ) + { + mlt_properties_set_int( MLT_FILTER_PROPERTIES(pdata->pitch_filter), "stretch", 1 ); + // Set the pitchscale to compensate for the difference between the input sampling frequency and the requested sampling frequency. + double pitchscale = (double)in_frequency / (double)requested_frequency; + mlt_properties_set_double( MLT_FILTER_PROPERTIES(pdata->pitch_filter), "pitchscale", pitchscale ); + mlt_filter_process( pdata->pitch_filter, frame ); + } + } + // Apply a resampler if rbpitch is not stretching to provide + if ( !pitch_compensate || !pdata->pitch_filter ) + { + if ( !pdata->resample_filter ) + { + pdata->resample_filter = mlt_factory_filter( mlt_service_profile( MLT_LINK_SERVICE(self) ), "resample", NULL ); + if ( !pdata->resample_filter ) + { + pdata->resample_filter = mlt_factory_filter( mlt_service_profile( MLT_LINK_SERVICE(self) ), "swresample", NULL ); + } + } + if ( pdata->resample_filter ) + { + mlt_filter_process( pdata->resample_filter, frame ); + } + } + + // Final call to get_audio() to apply the pitch or resample filter + *frequency = requested_frequency; + *samples = requested_samples; + int error = mlt_frame_get_audio( frame, audio, format, frequency, channels, samples ); + + return error; +} + +static int link_get_image_blend( mlt_frame frame, uint8_t** image, mlt_image_format* format, int* width, int* height, int writable ) +{ + static const int MAX_BLEND_IMAGES = 10; + mlt_link self = (mlt_link)mlt_frame_pop_get_image( frame ); + mlt_properties unique_properties = mlt_frame_get_unique_properties( frame, MLT_LINK_SERVICE(self) ); + if ( !unique_properties ) + { + return 1; + } + double source_time = mlt_properties_get_double( unique_properties, "source_time"); + double source_fps = mlt_properties_get_double( unique_properties, "source_fps"); + + // Get pointers to all the images for this frame + uint8_t* images[MAX_BLEND_IMAGES]; + int image_count = 0; + mlt_position in_frame_pos = floor( source_time * source_fps ); + int colorspace = 0; + while ( image_count < MAX_BLEND_IMAGES ) + { + char key[19]; + sprintf( key, "%d", in_frame_pos ); + mlt_frame src_frame = (mlt_frame)mlt_properties_get_data( unique_properties, key, NULL ); + if ( src_frame && !mlt_frame_get_image( src_frame, &images[image_count], format, width, height, 0 ) ) + { + colorspace = mlt_properties_get_int( MLT_FRAME_PROPERTIES(src_frame), "colorspace" ); + in_frame_pos++; + image_count++; + } + else + { + break; + } + } + + if ( image_count <= 0 ) + { + return 1; + } + + // Sum all the images into one image with 16 bit components + int size = mlt_image_format_size( *format, *width, *height, NULL ); + *image = mlt_pool_alloc( size ); + int s = 0; + uint8_t* p = *image; + for( s = 0; s < size; s++ ) + { + int16_t sum = 0; + int i = 0; + for( i = 0; i < image_count; i++ ) + { + sum += *(images[i]); + images[i]++; + } + *p = sum / image_count; + p++; + } + mlt_frame_set_image( frame, *image, size, mlt_pool_release ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "format", *format ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "width", *width ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "height", *height ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "colorspace", colorspace ); + + return 0; +} + +static int link_get_image_nearest( mlt_frame frame, uint8_t** image, mlt_image_format* format, int* width, int* height, int writable ) +{ + mlt_link self = (mlt_link)mlt_frame_pop_get_image( frame ); + mlt_properties unique_properties = mlt_frame_get_unique_properties( frame, MLT_LINK_SERVICE(self) ); + if ( !unique_properties ) + { + return 1; + } + double source_time = mlt_properties_get_double( unique_properties, "source_time"); + double source_fps = mlt_properties_get_double( unique_properties, "source_fps"); + mlt_position in_frame_pos = floor( source_time * source_fps ); + char key[19]; + sprintf( key, "%d", in_frame_pos ); + + mlt_frame src_frame = (mlt_frame)mlt_properties_get_data( unique_properties, key, NULL ); + if ( src_frame ) + { + uint8_t* in_image; + if ( !mlt_frame_get_image( src_frame, &in_image, format, width, height, 0 ) ) + { + int size = mlt_image_format_size( *format, *width, *height, NULL ); + *image = mlt_pool_alloc( size ); + memcpy( *image, in_image, size ); + mlt_frame_set_image( frame, *image, size, mlt_pool_release ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "format", *format ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "width", *width ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "height", *height ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "colorspace", mlt_properties_get_int( MLT_FRAME_PROPERTIES(src_frame), "colorspace" )); + + uint8_t* in_alpha = mlt_frame_get_alpha( src_frame ); + if ( in_alpha ) + { + size = *width * *height; + uint8_t* out_alpha = mlt_pool_alloc( size ); + memcpy( out_alpha, in_alpha, size ); + mlt_frame_set_alpha( frame, out_alpha, size, mlt_pool_release ); + }; + return 0; + } + } + + return 1; +} + +static int link_get_frame( mlt_link self, mlt_frame_ptr frame, int index ) +{ + mlt_properties properties = MLT_LINK_PROPERTIES( self ); + private_data* pdata = (private_data*)self->child; + mlt_position position = mlt_producer_position( MLT_LINK_PRODUCER( self ) ); + mlt_position length = mlt_producer_get_length( MLT_LINK_PRODUCER( self ) ); + double source_time = 0.0; + double source_duration = 0.0; + double source_fps = mlt_producer_get_fps( self->next ); + double link_fps = mlt_producer_get_fps( MLT_LINK_PRODUCER( self ) ); + + int result = 0; + + // Create a frame + *frame = mlt_frame_init( MLT_LINK_SERVICE(self) ); + mlt_frame_set_position( *frame, mlt_producer_position( MLT_LINK_PRODUCER(self) ) ); + mlt_properties unique_properties = mlt_frame_unique_properties( *frame, MLT_LINK_SERVICE(self) ); + + // Calculate the frames from the next link to be used + if ( !mlt_properties_exists( properties, "map" ) ) + { + source_time = (double)position / link_fps; + source_duration = 1.0 / link_fps; + } + else + { + // Assume that the user wants normal speed before the in point. + mlt_position in = mlt_producer_get_in( MLT_LINK_PRODUCER(self) ); + double in_time = (double)in / link_fps; + source_time = mlt_properties_anim_get_double( properties, "map", position - in, length ) + in_time; + double next_source_time = mlt_properties_anim_get_double( properties, "map", position - in + 1, length ) + in_time; + source_duration = next_source_time - source_time; + } + + double frame_duration = 1.0 / link_fps; + double source_speed = 0.0; + if ( source_duration != 0.0 ) + { + source_speed = source_duration / frame_duration; + } + + mlt_properties_set_double( unique_properties, "source_fps", source_fps ); + mlt_properties_set_double( unique_properties, "source_time", source_time ); + mlt_properties_set_double( unique_properties, "source_duration", source_duration ); + mlt_properties_set_double( unique_properties, "source_speed", source_speed ); + + mlt_log_debug( MLT_LINK_SERVICE(self), "Get Frame: %f -> %f\t%d\t%d\n", source_fps, link_fps, position, mlt_producer_get_in( MLT_LINK_PRODUCER(self) ) ); + + // Get frames from the next link and pass them along with the new frame + int in_frame_count = 0; + mlt_frame src_frame = NULL; + mlt_position prev_frame_position = pdata->prev_frame ? mlt_frame_get_position( pdata->prev_frame ) : -1; + mlt_position in_frame_pos = floor( source_time * source_fps ); + double frame_time = (double)in_frame_pos / source_fps; + double source_end_time = source_time + fabs(source_duration); + if ( frame_time == source_end_time ) + { + // Force one frame to be sent. + source_end_time += 0.0000000001; + } + while ( frame_time < source_end_time ) + { + if( in_frame_pos == prev_frame_position ) + { + // Reuse the previous frame to avoid seeking. + src_frame = pdata->prev_frame; + mlt_properties_inc_ref( MLT_FRAME_PROPERTIES(src_frame) ); + } + else + { + mlt_producer_seek( self->next, in_frame_pos ); + result = mlt_service_get_frame( MLT_PRODUCER_SERVICE( self->next ), &src_frame, index ); + if ( result ) + { + break; + } + } + // Save the source frame on the output frame + char key[19]; + sprintf( key, "%d", in_frame_pos ); + mlt_properties_set_data( unique_properties, key, src_frame, 0, (mlt_destructor)mlt_frame_close, NULL ); + + // Calculate the next frame + in_frame_pos++; + frame_time = (double)in_frame_pos / source_fps; + in_frame_count++; + } + + if ( !src_frame ) + { + mlt_frame_close( *frame ); + *frame = NULL; + return 1; + } + + // Copy some useful properties from one of the source frames. + (*frame)->convert_image = src_frame->convert_image; + (*frame)->convert_audio = src_frame->convert_audio; + mlt_properties_pass_list( MLT_FRAME_PROPERTIES(*frame), MLT_FRAME_PROPERTIES(src_frame), "audio_frequency" ); + + if ( src_frame != pdata->prev_frame ) + { + // Save the last source frame because it might be requested for the next frame. + mlt_frame_close( pdata->prev_frame ); + mlt_properties_inc_ref( MLT_FRAME_PROPERTIES(src_frame) ); + pdata->prev_frame = src_frame; + } + + // Setup callbacks + char* mode = mlt_properties_get( properties, "image_mode" ); + mlt_frame_push_get_image( *frame, (void*)self ); + if ( in_frame_count == 1 || !mode || !strcmp( mode, "nearest" ) ) + { + mlt_frame_push_get_image( *frame, link_get_image_nearest ); + } + else + { + mlt_frame_push_get_image( *frame, link_get_image_blend ); + } + + mlt_frame_push_audio( *frame, (void*)self ); + mlt_frame_push_audio( *frame, link_get_audio ); + + mlt_producer_prepare_next( MLT_LINK_PRODUCER( self ) ); + mlt_properties_set_double( properties, "speed", source_speed ); + + return result; +} + +static void link_close( mlt_link self ) +{ + if ( self ) + { + private_data* pdata = (private_data*)self->child; + if ( pdata ) + { + if ( pdata->prev_frame ) + { + mlt_frame_close( pdata->prev_frame ); + } + if ( pdata->resample_filter ) + { + mlt_filter_close( pdata->resample_filter ); + } + if ( pdata->pitch_filter ) + { + mlt_filter_close( pdata->pitch_filter ); + } + free( pdata ); + } + self->close = NULL; + mlt_link_close( self ); + free( self ); + } +} + +mlt_link link_timeremap_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) +{ + mlt_link self = mlt_link_init(); + private_data* pdata = (private_data*)calloc( 1, sizeof(private_data) ); + + if ( self && pdata ) + { + self->child = pdata; + + // Callback registration + self->configure = link_configure; + self->get_frame = link_get_frame; + self->close = link_close; + } + else + { + if ( pdata ) + { + free( pdata ); + } + + if ( self ) + { + mlt_link_close( self ); + self = NULL; + } + } + return self; +} diff --git a/src/modules/core/link_timeremap.yml b/src/modules/core/link_timeremap.yml new file mode 100644 index 000000000..b72ffbff6 --- /dev/null +++ b/src/modules/core/link_timeremap.yml @@ -0,0 +1,33 @@ +schema_version: 7.0 +type: link +identifier: timeremap +title: Time Remap +version: 1 +copyright: Meltytech, LLC +license: LGPLv2.1 +language: en +tags: + - Audio + - Video +description: Remap frames in time. +parameters: + - identifier: map + title: Map + type: float + description: > + A map of input frame times to output frame times. + mutable: yes + animation: yes + - identifier: image_mode + title: Image Mode + type: string + description: The image mode to use. + values: + - nearest # Output the nearest frame + - blend # Blend the frames that make up the output + mutable: yes + - identifier: speed + title: Speed + type: float + description: The instantaneous speed of the last frame that was processed. + readonly: yes diff --git a/src/modules/core/loader.dict b/src/modules/core/loader.dict index fb666f945..d18deb04a 100644 --- a/src/modules/core/loader.dict +++ b/src/modules/core/loader.dict @@ -8,12 +8,8 @@ plain:https://*=webvfx:plain: *.kdenlive=xml *.melt=melt_file *.inigo=melt_file -*.asf=avformat -*.avi=mcdv,avformat,libdv *.bmp=qimage,pixbuf *.dds=qimage,avformat -*.dv=mcdv,avformat,libdv -*.dif=mcdv,avformat,libdv *.exr=qimage *.gif=qimage,pixbuf *.graphics=xml @@ -28,10 +24,6 @@ plain:https://*=webvfx:plain: *.kdenlivetitle=kdenlivetitle *.kino=xml *.kra=qimage -*.mp3=avformat -*.mov=mcdv,avformat,libdv -*.mpg=mcmpeg,avformat -*.mpeg=mcmpeg,avformat *.mpl=pango *.ogg=avformat,vorbis *.pcx=qimage,pixbuf @@ -41,15 +33,11 @@ plain:https://*=webvfx:plain: *.qml=webvfx:plain: *.story=xml *.svg=qimage,pixbuf -*.swf=avformat,swfdec *.tga=qimage,pixbuf *.tif=qimage,pixbuf *.tiff=qimage,pixbuf *.txt=qtext,pango -*.vob=mcmpeg,avformat -*.wav=avformat *.webp=qimage,avformat -*.wmv=avformat *.xcf=qimage *.xml=xml *=avformat diff --git a/src/modules/core/loader.ini b/src/modules/core/loader.ini index d861e3b29..99d3987ee 100644 --- a/src/modules/core/loader.ini +++ b/src/modules/core/loader.ini @@ -16,6 +16,3 @@ resizer=movit.resize,resize # audio filters channels=swresample,audiochannels resampler=resample - -# metadata filters -data=data_feed:attr_check diff --git a/src/modules/core/producer_colour.c b/src/modules/core/producer_colour.c index 3c670f778..8e7897465 100644 --- a/src/modules/core/producer_colour.c +++ b/src/modules/core/producer_colour.c @@ -91,16 +91,16 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form *format = mlt_image_format_id( mlt_properties_get( producer_props, "mlt_image_format") ); // Choose suitable out values if nothing specific requested - if ( *format == mlt_image_none || *format == mlt_image_glsl ) - *format = mlt_image_rgb24a; + if ( *format == mlt_image_none || *format == mlt_image_movit ) + *format = mlt_image_rgba; if ( *width <= 0 ) *width = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->width; if ( *height <= 0 ) *height = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->height; // Choose default image format if specific request is unsupported - if (*format!=mlt_image_yuv420p && *format!=mlt_image_yuv422 && *format!=mlt_image_rgb24 && *format!= mlt_image_glsl && *format!= mlt_image_glsl_texture) - *format = mlt_image_rgb24a; + if (*format!=mlt_image_yuv420p && *format!=mlt_image_yuv422 && *format!=mlt_image_rgb && *format!= mlt_image_movit && *format!= mlt_image_opengl_texture) + *format = mlt_image_rgba; // See if we need to regenerate if ( !now || ( then && strcmp( now, then ) ) || *width != current_width || *height != current_height || *format != current_format ) @@ -163,7 +163,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form mlt_properties_set_int( properties, "colorspace", 601 ); break; } - case mlt_image_rgb24: + case mlt_image_rgb: while ( --i ) { *p ++ = color.r; @@ -171,11 +171,11 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form *p ++ = color.b; } break; - case mlt_image_glsl: - case mlt_image_glsl_texture: + case mlt_image_movit: + case mlt_image_opengl_texture: memset(p, 0, size); break; - case mlt_image_rgb24a: + case mlt_image_rgba: while ( --i ) { *p ++ = color.r; @@ -199,7 +199,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form uint8_t *alpha = NULL; // Initialise the alpha - if (color.a < 255 || *format == mlt_image_rgb24a) { + if (color.a < 255 || *format == mlt_image_rgba) { alpha_size = *width * *height; alpha = mlt_pool_alloc( alpha_size ); if ( alpha ) diff --git a/src/modules/core/producer_consumer.c b/src/modules/core/producer_consumer.c index 4e2debdb9..14283c09a 100644 --- a/src/modules/core/producer_consumer.c +++ b/src/modules/core/producer_consumer.c @@ -1,6 +1,6 @@ /* * producer_consumer.c -- produce as a consumer of an encapsulated producer - * Copyright (C) 2008-2020 Meltytech, LLC + * Copyright (C) 2008-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 @@ -104,7 +104,7 @@ static int get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, return result; } -static void property_changed( mlt_properties owner, mlt_consumer self, char *name ) +static void property_changed( mlt_properties owner, mlt_consumer self, mlt_event_data event_data ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES(self); context cx = mlt_properties_get_data( properties, "context", NULL ); @@ -112,11 +112,12 @@ static void property_changed( mlt_properties owner, mlt_consumer self, char *nam if ( !cx ) return; - if ( name == strstr( name, CONSUMER_PROPERTIES_PREFIX ) ) + const char *name = mlt_event_data_to_string(event_data); + if ( name && name == strstr( name, CONSUMER_PROPERTIES_PREFIX ) ) mlt_properties_set(MLT_CONSUMER_PROPERTIES( cx->consumer ), name + strlen( CONSUMER_PROPERTIES_PREFIX ), mlt_properties_get( properties, name )); - if ( name == strstr( name, PRODUCER_PROPERTIES_PREFIX ) ) + if ( name && name == strstr( name, PRODUCER_PROPERTIES_PREFIX ) ) mlt_properties_set(MLT_PRODUCER_PROPERTIES( cx->producer ), name + strlen( PRODUCER_PROPERTIES_PREFIX ), mlt_properties_get( properties, name )); } diff --git a/src/modules/core/producer_loader.c b/src/modules/core/producer_loader.c index 1f81cb84f..fc793764a 100644 --- a/src/modules/core/producer_loader.c +++ b/src/modules/core/producer_loader.c @@ -230,7 +230,7 @@ mlt_producer producer_loader_init( mlt_profile profile, mlt_service_type type, c mlt_properties_get( properties, "loader_normalised" ) == NULL ) attach_normalisers( profile, producer ); - if ( producer ) + if ( producer && mlt_service_identify( MLT_PRODUCER_SERVICE( producer ) ) != mlt_service_chain_type ) { // Always let the image and audio be converted int created = 0; diff --git a/src/modules/core/producer_melt.c b/src/modules/core/producer_melt.c index 9d9cc8a67..f704831fc 100644 --- a/src/modules/core/producer_melt.c +++ b/src/modules/core/producer_melt.c @@ -130,6 +130,19 @@ static mlt_transition create_transition( mlt_profile profile, mlt_field field, c return transition; } +static mlt_link create_link( mlt_field field, char *id ) +{ + char *temp = strdup( id ); + char *arg = strchr( temp, ':' ); + if ( arg != NULL ) + *arg ++ = '\0'; + mlt_link link = mlt_factory_link( temp, arg ); + if ( link != NULL ) + track_service( field, link, ( mlt_destructor )mlt_link_close ); + free( temp ); + return link; +} + mlt_producer producer_melt_init( mlt_profile profile, mlt_service_type type, const char *id, char **argv ) { int i; @@ -143,6 +156,7 @@ mlt_producer producer_melt_init( mlt_profile profile, mlt_service_type type, con mlt_field field = mlt_tractor_field( tractor ); mlt_properties field_properties = mlt_field_properties( field ); mlt_multitrack multitrack = mlt_tractor_multitrack( tractor ); + mlt_chain chain = NULL; char *title = NULL; // Assistance for template construction (allows -track usage to specify the first track) @@ -418,6 +432,41 @@ mlt_producer producer_melt_init( mlt_profile profile, mlt_service_type type, con mlt_properties_set_int( properties, "hide", 2 ); } } + else if ( !strcmp( argv[ i ], "-chain" ) ) + { + if ( chain == NULL && producer != NULL && !mlt_producer_is_cut( producer ) ) + mlt_playlist_append( playlist, producer ); + else if ( chain != NULL && mlt_chain_get_source( chain ) != NULL ) + { + mlt_playlist_append( playlist, producer ); + } + + chain = mlt_chain_init( profile ); + if ( chain != NULL ) + { + producer = MLT_CHAIN_PRODUCER( chain ); + properties = MLT_PRODUCER_PROPERTIES( producer ); + mlt_properties_inherit( properties, group ); + track_service( field, chain, ( mlt_destructor )mlt_chain_close ); + } + } + else if ( !strcmp( argv[ i ], "-link" ) ) + { + if ( chain == NULL || mlt_chain_get_source( chain ) == NULL ) + { + fprintf( stderr, "A link can only be added to a chain with a producer.\n" ); + } + else + { + mlt_link link = create_link( field, argv[ ++ i ] ); + if ( link != NULL ) + { + mlt_chain_attach( chain, link ); + properties = MLT_LINK_PROPERTIES( link ); + mlt_properties_inherit( properties, group ); + } + } + } else if ( strchr( argv[ i ], '=' ) && strstr( argv[ i ], " + * 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 @@ -39,9 +38,11 @@ typedef struct // Private Functions -static void timewarp_property_changed( mlt_service owner, mlt_producer producer, char *name ) +static void timewarp_property_changed( mlt_service owner, mlt_producer producer, mlt_event_data event_data ) { private_data* pdata = (private_data*)producer->child; + const char *name = mlt_event_data_to_string(event_data); + if ( mlt_properties_get_int( pdata->clip_parameters, name ) || !strcmp( name, "length" ) || !strcmp( name, "in" ) || @@ -60,9 +61,11 @@ static void timewarp_property_changed( mlt_service owner, mlt_producer producer, } } -static void clip_property_changed( mlt_service owner, mlt_producer producer, char *name ) +static void clip_property_changed( mlt_service owner, mlt_producer producer, mlt_event_data event_data ) { private_data* pdata = (private_data*)producer->child; + const char *name = mlt_event_data_to_string(event_data); + if ( mlt_properties_get_int( pdata->clip_parameters, name ) || !strcmp( name, "length" ) || !strcmp( name, "in" ) || @@ -278,7 +281,7 @@ mlt_producer producer_timewarp_init( mlt_profile profile, mlt_service_type type, // they can be passed between the clip producer and this producer. pdata->clip_parameters = mlt_properties_new(); mlt_repository repository = mlt_factory_repository(); - mlt_properties clip_metadata = mlt_repository_metadata( repository, producer_type, mlt_properties_get( clip_properties, "mlt_service" ) ); + mlt_properties clip_metadata = mlt_repository_metadata( repository, mlt_service_producer_type, mlt_properties_get( clip_properties, "mlt_service" ) ); if ( clip_metadata ) { mlt_properties params = (mlt_properties) mlt_properties_get_data( clip_metadata, "parameters", NULL ); diff --git a/src/modules/core/producer_timewarp.yml b/src/modules/core/producer_timewarp.yml index 9252407e4..4df6c2137 100644 --- a/src/modules/core/producer_timewarp.yml +++ b/src/modules/core/producer_timewarp.yml @@ -4,7 +4,6 @@ identifier: timewarp title: Time Warp version: 1 copyright: Meltytech, LLC -creator: Brian Matherly license: LGPLv2.1 language: en tags: diff --git a/src/modules/core/producer_tone.c b/src/modules/core/producer_tone.c index 3766c87a8..6b183150a 100644 --- a/src/modules/core/producer_tone.c +++ b/src/modules/core/producer_tone.c @@ -1,7 +1,6 @@ /* * producer_tone.c -- audio tone generating producer * Copyright (C) 2014 Meltytech, LLC - * Author: Brian Matherly * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/modules/core/producer_tone.yml b/src/modules/core/producer_tone.yml index 24cf654f3..ffd34e9ae 100644 --- a/src/modules/core/producer_tone.yml +++ b/src/modules/core/producer_tone.yml @@ -4,7 +4,6 @@ identifier: tone title: Tone version: 1 copyright: Meltytech, LLC -creator: Brian Matherly license: LGPLv2.1 language: en tags: diff --git a/src/modules/core/transition_composite.c b/src/modules/core/transition_composite.c index f382ba1b8..636902864 100644 --- a/src/modules/core/transition_composite.c +++ b/src/modules/core/transition_composite.c @@ -1,6 +1,6 @@ /* * transition_composite.c -- compose one image over another using alpha channel - * Copyright (C) 2003-2020 Meltytech, LLC + * Copyright (C) 2003-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 @@ -26,6 +26,7 @@ #include #include #include +#include typedef void ( *composite_line_fn )( uint8_t *dest, uint8_t *src, int width_src, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int softness, uint32_t step ); @@ -34,7 +35,7 @@ typedef void ( *composite_line_fn )( uint8_t *dest, uint8_t *src, int width_src, struct geometry_s { - struct mlt_geometry_item_s item; + mlt_rect item; int nw; // normalised width int nh; // normalised height int sw; // scaled width, not including consumer scale based upon w/nw @@ -63,105 +64,6 @@ static int alignment_parse( char* align ) return ret; } -/** Calculate real geometry. -*/ - -static void geometry_calculate( mlt_transition self, struct geometry_s *output, double position ) -{ - mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); - mlt_geometry geometry = mlt_properties_get_data( properties, "geometries", NULL ); - int mirror_off = mlt_properties_get_int( properties, "mirror_off" ); - int repeat_off = mlt_properties_get_int( properties, "repeat_off" ); - int length = mlt_geometry_get_length( geometry ); - - // Allow wrapping - if ( !repeat_off && position >= length && length != 0 ) - { - int section = position / length; - position -= section * length; - if ( !mirror_off && section % 2 == 1 ) - position = length - position; - } - - // Fetch the key for the position - mlt_geometry_fetch( geometry, &output->item, position ); -} - -static mlt_geometry transition_parse_keys( mlt_transition self, int normalised_width, int normalised_height ) -{ - // Loop variable for property interrogation - int i = 0; - - // Get the properties of the transition - mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); - - // Create an empty geometries object - mlt_geometry geometry = mlt_geometry_init( ); - - // Get the duration - mlt_position length = mlt_transition_get_length( self ); - double cycle = mlt_properties_get_double( properties, "cycle" ); - - // Get the new style geometry string - char *property = mlt_properties_get( properties, "geometry" ); - - // Allow a geometry repeat cycle - if ( cycle >= 1 ) - length = cycle; - else if ( cycle > 0 ) - length *= cycle; - - // Parse the geometry if we have one - mlt_geometry_parse( geometry, property, length, normalised_width, normalised_height ); - - // Check if we're using the old style geometry - if ( property == NULL ) - { - // DEPRECATED: Multiple keys for geometry information is inefficient and too rigid for - // practical use - while deprecated, it has been slightly extended too - keys can now - // be specified out of order, and can be blanked or NULL to simulate removal - - // Structure to use for parsing and inserting - struct mlt_geometry_item_s item; - - // Parse the start property - item.frame = 0; - if ( mlt_geometry_parse_item( geometry, &item, mlt_properties_get( properties, "start" ) ) == 0 ) - mlt_geometry_insert( geometry, &item ); - - // Parse the keys in between - for ( i = 0; i < mlt_properties_count( properties ); i ++ ) - { - // Get the name of the property - char *name = mlt_properties_get_name( properties, i ); - - // Check that it's valid - if ( !strncmp( name, "key[", 4 ) ) - { - // Get the value of the property - char *value = mlt_properties_get_value( properties, i ); - - // Determine the frame number - item.frame = atoi( name + 4 ); - - // Parse and add to the list - if ( mlt_geometry_parse_item( geometry, &item, value ) == 0 ) - mlt_geometry_insert( geometry, &item ); - else - fprintf( stderr, "Invalid Key - skipping %s = %s\n", name, value ); - } - } - - // Parse the end - item.frame = -1; - if ( mlt_geometry_parse_item( geometry, &item, mlt_properties_get( properties, "end" ) ) == 0 ) - mlt_geometry_insert( geometry, &item ); - mlt_geometry_interpolate( geometry ); - } - - return geometry; -} - /** Adjust position according to scaled size and alignment properties. */ @@ -371,8 +273,8 @@ static int composite_yuv( uint8_t *p_dest, int width_dest, int height_dest, uint int stride_src = geometry->sw * bpp; int stride_dest = width_dest * bpp; int i_softness = ( 1 << 16 ) * softness; - int weight = ( ( 1 << 16 ) * geometry->item.mix + 50 ) / 100; - uint32_t luma_step = ( ( ( 1 << 16 ) - 1 ) * geometry->item.mix + 50 ) / 100 * ( 1.0 + softness ); + int weight = ( ( 1 << 16 ) * geometry->item.o + 50 ) / 100; + uint32_t luma_step = ( ( ( 1 << 16 ) - 1 ) * geometry->item.o + 50 ) / 100 * ( 1.0 + softness ); // Adjust to consumer scale int x = rint( geometry->item.x * width_dest / geometry->nw ); @@ -770,7 +672,7 @@ static int get_b_frame_image( mlt_transition self, mlt_frame b_frame, uint8_t ** geometry->sh = scaled_height; } // Normalise aspect ratios and scale preserving aspect ratio - else if ( mlt_properties_get_int( properties, "aligned" ) && mlt_properties_get_int( properties, "distort" ) == 0 && mlt_properties_get_int( b_props, "distort" ) == 0 && geometry->item.distort == 0 ) + else if ( mlt_properties_get_int( properties, "aligned" ) && mlt_properties_get_int( properties, "distort" ) == 0 && mlt_properties_get_int( b_props, "distort" ) == 0 ) { // Adjust b_frame pixel aspect int normalised_width = geometry->item.w; @@ -856,228 +758,105 @@ static int get_b_frame_image( mlt_transition self, mlt_frame b_frame, uint8_t ** return !error && image; } -static void crop_calculate( mlt_transition self, mlt_properties properties, struct geometry_s *result, double position ) +static void crop_calculate( mlt_transition self, struct geometry_s *result, double position ) { + // Get the properties from the transition + mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); + // Initialize panning info result->x_src = 0; result->y_src = 0; if ( mlt_properties_get( properties, "crop" ) ) { - mlt_geometry crop = mlt_properties_get_data( properties, "crop_geometry", NULL ); - if ( !crop ) - { - crop = mlt_geometry_init(); - mlt_position length = mlt_transition_get_length( self ); - double cycle = mlt_properties_get_double( properties, "cycle" ); - - // Allow a geometry repeat cycle - if ( cycle >= 1 ) - length = cycle; - else if ( cycle > 0 ) - length *= cycle; - mlt_geometry_parse( crop, mlt_properties_get( properties, "crop" ), length, result->sw, result->sh ); - mlt_properties_set_data( properties, "crop_geometry", crop, 0, (mlt_destructor)mlt_geometry_close, NULL ); - } + mlt_position length = mlt_transition_get_length( self ); + double cycle = mlt_properties_get_double( properties, "cycle" ); + + // Allow a geometry repeat cycle + if ( cycle >= 1 ) + length = cycle; + else if ( cycle > 0 ) + length *= cycle; + + mlt_rect crop = mlt_properties_anim_get_rect(properties, "crop", position, length); // Repeat processing - int length = mlt_geometry_get_length( crop ); + mlt_animation animation = mlt_properties_get_animation(properties, "crop"); + int anim_length = mlt_animation_get_length(animation); int mirror_off = mlt_properties_get_int( properties, "mirror_off" ); int repeat_off = mlt_properties_get_int( properties, "repeat_off" ); - if ( !repeat_off && position >= length && length != 0 ) + if ( !repeat_off && position >= anim_length && anim_length != 0 ) { - int section = position / length; - position -= section * length; + int section = position / anim_length; + position -= section * anim_length; if ( !mirror_off && section % 2 == 1 ) - position = length - position; + position = anim_length - position; } // Compute the pan - struct mlt_geometry_item_s crop_item; - mlt_geometry_fetch( crop, &crop_item, position ); - result->x_src = rint( crop_item.x ); - result->y_src = rint( crop_item.y ); + crop = mlt_properties_anim_get_rect(properties, "crop", position, length); + if (mlt_properties_get(properties, "crop") && strchr(mlt_properties_get(properties, "crop"), '%')) { + mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( self ) ); + crop.x *= profile->width; + crop.y *= profile->height; + } + result->x_src = rint( crop.x ); + result->y_src = rint( crop.y ); } } -static mlt_geometry composite_calculate( mlt_transition self, struct geometry_s *result, mlt_frame a_frame, double position ) +static void composite_calculate( mlt_transition self, struct geometry_s *result, double position ) { // Get the properties from the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); - // Get the properties from the frame - mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); - - // Structures for geometry - mlt_geometry start = mlt_properties_get_data( properties, "geometries", NULL ); - // Obtain the normalised width and height from the a_frame mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( self ) ); int normalised_width = profile->width; int normalised_height = profile->height; - char *name = mlt_properties_get( properties, "_unique_id" ); - char key[ 256 ]; - - snprintf( key, sizeof(key), "composite %s.in", name ); - if ( mlt_properties_get( a_props, key ) ) - { - sscanf( mlt_properties_get( a_props, key ), "%f %f %f %f %f %d %d", &result->item.x, &result->item.y, &result->item.w, &result->item.h, &result->item.mix, &result->nw, &result->nh ); - } - else - { - // Now parse the geometries - if ( start == NULL ) - { - // Parse the transitions properties - start = transition_parse_keys( self, normalised_width, normalised_height ); - - // Assign to properties to ensure we get destroyed - mlt_properties_set_data( properties, "geometries", start, 0, ( mlt_destructor )mlt_geometry_close, NULL ); - } - else - { - mlt_position length = mlt_transition_get_length( self ); - double cycle = mlt_properties_get_double( properties, "cycle" ); - if ( cycle > 1 ) - length = cycle; - else if ( cycle > 0 ) - length *= cycle; - mlt_geometry_refresh( start, mlt_properties_get( properties, "geometry" ), length, normalised_width, normalised_height ); - } - - // Do the calculation - geometry_calculate( self, result, position ); - - // Assign normalised info - result->nw = normalised_width; - result->nh = normalised_height; - } - - // Now parse the alignment - result->halign = alignment_parse( mlt_properties_get( properties, "halign" ) ); - result->valign = alignment_parse( mlt_properties_get( properties, "valign" ) ); - - crop_calculate( self, properties, result, position ); - - return start; -} - -mlt_frame composite_copy_region( mlt_transition self, mlt_frame a_frame, mlt_position frame_position ) -{ - // Create a frame to return - mlt_frame b_frame = mlt_frame_init( MLT_TRANSITION_SERVICE( self ) ); - b_frame->convert_image = a_frame->convert_image; - - // Get the properties of the a frame - mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); - - // Get the properties of the b frame - mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); - - // Get the position - int position = position_calculate( self, frame_position ); - - // Get the unique id of the transition - char *name = mlt_properties_get( MLT_TRANSITION_PROPERTIES( self ), "_unique_id" ); - char key[ 256 ]; - - // Destination image - uint8_t *dest = NULL; - - // Get the image and dimensions - uint8_t *image = NULL; - int width = mlt_properties_get_int( a_props, "width" ); - int height = mlt_properties_get_int( a_props, "height" ); - mlt_image_format format = mlt_image_yuv422; - - mlt_frame_get_image( a_frame, &image, &format, &width, &height, 0 ); - if ( !image ) - return b_frame; - - // Pointers for copy operation - uint8_t *p; - - // Coordinates - int w = 0; - int h = 0; - int x = 0; - int y = 0; - - int ss = 0; - int ds = 0; - - // Will need to know region to copy - struct geometry_s result; - - // Calculate the region now - composite_calculate( self, &result, a_frame, position ); - - // Need to scale down to actual dimensions - x = rint( result.item.x * width / result.nw ); - y = rint( result.item.y * height / result.nh ); - w = rint( result.item.w * width / result.nw ); - h = rint( result.item.h * height / result.nh ); - - if ( x % 2 ) - { - x --; - w ++; - } - - // Store the key - snprintf( key, sizeof(key), "composite %s.in=%d %d %d %d %f %d %d", name, x, y, w, h, result.item.mix, width, height ); - mlt_properties_parse( a_props, key ); - snprintf( key, sizeof(key), "composite %s.out=%d %d %d %d %f %d %d", name, x, y, w, h, result.item.mix, width, height ); - mlt_properties_parse( a_props, key ); - - ds = w * 2; - ss = width * 2; + // Now parse the geometries + mlt_position length = mlt_transition_get_length( self ); + double cycle = mlt_properties_get_double( properties, "cycle" ); - // Now we need to create a new destination image - dest = mlt_pool_alloc( w * h * 2 ); + // Allow a geometry repeat cycle + if ( cycle >= 1 ) + length = cycle; + else if ( cycle > 0 ) + length *= cycle; - // Assign to the new frame - mlt_frame_set_image( b_frame, dest, w * h * 2, mlt_pool_release ); - mlt_properties_set_int( b_props, "width", w ); - mlt_properties_set_int( b_props, "height", h ); - mlt_properties_set_int( b_props, "format", format ); + result->item = mlt_properties_anim_get_rect(properties, "geometry", position, length); - if ( y < 0 ) + // Repeat processing + mlt_animation animation = mlt_properties_get_animation(properties, "geometry"); + int anim_length = mlt_animation_get_length(animation); + int mirror_off = mlt_properties_get_int( properties, "mirror_off" ); + int repeat_off = mlt_properties_get_int( properties, "repeat_off" ); + if ( !repeat_off && position >= anim_length && anim_length != 0 ) { - dest += ( ds * -y ); - h += y; - y = 0; + int section = position / anim_length; + position -= section * anim_length; + if ( !mirror_off && section % 2 == 1 ) + position = anim_length - position; } + result->item = mlt_properties_anim_get_rect(properties, "geometry", position, length); - if ( y + h > height ) - h -= ( y + h - height ); - - if ( x < 0 ) - { - dest += -x * 2; - w += x; - x = 0; + if (mlt_properties_get(properties, "geometry") && strchr(mlt_properties_get(properties, "geometry"), '%')) { + result->item.x *= normalised_width; + result->item.y *= normalised_height; + result->item.w *= normalised_width; + result->item.h *= normalised_height; } + result->item.o = 100.0 * (result->item.o == DBL_MIN ? 1.0 : MIN(result->item.o, 1.0)); - if ( w > 0 && h > 0 ) - { - // Copy the region of the image - p = image + y * ss + x * 2; + // Assign normalised info + result->nw = normalised_width; + result->nh = normalised_height; - while ( h -- ) - { - memcpy( dest, p, w * 2 ); - dest += ds; - p += ss; - } - } - - // Assign this position to the b frame - mlt_frame_set_position( b_frame, frame_position ); - mlt_properties_set_int( b_props, "distort", 1 ); + // Now parse the alignment + result->halign = alignment_parse( mlt_properties_get( properties, "halign" ) ); + result->valign = alignment_parse( mlt_properties_get( properties, "valign" ) ); - // Return the frame - return b_frame; + crop_calculate( self, result, position ); } /** Get the image. @@ -1145,7 +924,7 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f // Do the calculation // NB: Locks needed here since the properties are being modified mlt_service_lock( MLT_TRANSITION_SERVICE( self ) ); - composite_calculate( self, &result, a_frame, position ); + composite_calculate( self, &result, position ); mlt_service_unlock( MLT_TRANSITION_SERVICE( self ) ); // Manual option to deinterlace @@ -1157,7 +936,7 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f // TODO: Dangerous/temporary optimisation - if nothing to do, then do nothing if ( mlt_properties_get_int( properties, "no_alpha" ) && - result.item.x == 0 && result.item.y == 0 && result.item.w == *width && result.item.h == *height && result.item.mix == 100 ) + result.item.x == 0 && result.item.y == 0 && result.item.w == *width && result.item.h == *height && result.item.o == 100 ) { mlt_frame_get_image( b_frame, image, format, width, height, 1 ); if ( !mlt_frame_is_test_card( a_frame ) ) @@ -1178,7 +957,7 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f alpha_a = mlt_frame_get_alpha( a_frame ); // Optimisation - no compositing required - if ( result.item.mix == 0 || ( result.item.w == 0 && result.item.h == 0 ) ) + if ( result.item.o == 0 || ( result.item.w == 0 && result.item.h == 0 ) ) return 0; // Need to keep the width/height of the a_frame on the b_frame for titling @@ -1251,7 +1030,7 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f // Do the calculation if we need to // NB: Locks needed here since the properties are being modified mlt_service_lock( MLT_TRANSITION_SERVICE( self ) ); - composite_calculate( self, &result, a_frame, field_position ); + composite_calculate( self, &result, field_position ); mlt_service_unlock( MLT_TRANSITION_SERVICE( self ) ); if ( mlt_properties_get_int( properties, "titles" ) ) @@ -1344,7 +1123,7 @@ mlt_transition transition_composite_init( mlt_profile profile, mlt_service_type self->process = composite_process; // Default starting motion and zoom - mlt_properties_set( properties, "start", arg != NULL ? arg : "0/0:100%x100%" ); + mlt_properties_set( properties, "geometry", arg != NULL ? arg : "0/0:100%x100%" ); // Default factory mlt_properties_set( properties, "factory", mlt_environment( "MLT_PRODUCER" ) ); diff --git a/src/modules/core/transition_composite.h b/src/modules/core/transition_composite.h index e13be2331..d86a1b08b 100644 --- a/src/modules/core/transition_composite.h +++ b/src/modules/core/transition_composite.h @@ -1,6 +1,6 @@ /* * transition_composite.h -- compose one image over another using alpha channel - * Copyright (C) 2003-2014 Meltytech, LLC + * Copyright (C) 2003-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 @@ -24,8 +24,6 @@ extern mlt_transition transition_composite_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -// Courtesy functionality - allows regionalised filtering -extern mlt_frame composite_copy_region( mlt_transition, mlt_frame, mlt_position ); extern void composite_line_yuv( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft, uint32_t step ); diff --git a/src/modules/core/transition_composite.yml b/src/modules/core/transition_composite.yml index 7affb3974..622e349aa 100644 --- a/src/modules/core/transition_composite.yml +++ b/src/modules/core/transition_composite.yml @@ -2,7 +2,7 @@ schema_version: 0.3 type: transition identifier: composite title: Composite -version: 1 +version: 2 copyright: Meltytech, LLC creator: Dan Dennedy license: LGPLv2.1 @@ -32,10 +32,8 @@ parameters: - identifier: geometry title: Geometry - type: geometry - description: > - Key frame specification. This is a ";" delimited form of the deprecated - start, key[n], end properties. + type: rect + description: A possibly keyframed rectangle mutable: yes - identifier: progressive @@ -126,29 +124,6 @@ parameters: readonly: no mutable: yes - - identifier: start - title: Start geometry - description: > - (deprecated) A geometry specification as X/Y:WxH[!][:mix] - - X, Y, W, H are assumed to pixel units unless they have the suffix '%'. - - '!' is a shortcut to specify distort. - - Mix is always a 2 digit percentage, defaults to 100. - type: geometry - default: "0%/0%:100%x100%" - readonly: no - mutable: yes - - - identifier: end - title: End geometry - description: > - (deprecated) X/Y:WxH[:mix] - The end geometry specification (see "start"). - type: geometry - readonly: no - mutable: yes - - identifier: sliced_composite title: Use sliced compositing description: > @@ -159,16 +134,6 @@ parameters: mutable: yes widget: checkbox - - identifier: key[F] - title: Key frame geometry - description: > - (deprecated) X/Y:WxH[:mix] - set a key frame for geometry between the in - and out. F is a frame number and can be negative to make it relative to - the out point. - type: geometry - readonly: no - mutable: yes - - identifier: fill title: Fill geometry description: > diff --git a/src/modules/core/transition_luma.c b/src/modules/core/transition_luma.c index f9facfa67..d11b710f2 100644 --- a/src/modules/core/transition_luma.c +++ b/src/modules/core/transition_luma.c @@ -118,9 +118,9 @@ static inline int dissolve_yuv( mlt_frame frame, mlt_frame that, float weight, i if ( mlt_properties_get( &frame->parent, "distort" ) ) mlt_properties_set( &that->parent, "distort", mlt_properties_get( &frame->parent, "distort" ) ); mlt_frame_get_image( frame, &p_dest, &format, &width, &height, 1 ); - alpha_dst = mlt_frame_get_alpha_mask( frame ); + alpha_dst = mlt_frame_get_alpha( frame ); mlt_frame_get_image( that, &p_src, &format, &width_src, &height_src, 0 ); - alpha_src = mlt_frame_get_alpha_mask( that ); + alpha_src = mlt_frame_get_alpha( that ); int is_translucent = ( alpha_dst && !is_opaque(alpha_dst, width, height) ) || ( alpha_src && !is_opaque(alpha_src, width_src, height_src) ); @@ -148,8 +148,8 @@ static inline int dissolve_yuv( mlt_frame frame, mlt_frame that, float weight, i composite_line_yuv( p_dest, p_src, width_src, alpha_src, alpha_dst, mix, NULL, 0, 0 ); p_src += width_src << 1; p_dest += width << 1; - alpha_src += width_src; - alpha_dst += width; + if ( alpha_src ) alpha_src += width_src; + if ( alpha_dst ) alpha_dst += width; } } @@ -205,9 +205,9 @@ static void luma_composite( mlt_frame a_frame, mlt_frame b_frame, int luma_width if ( mlt_properties_get( &a_frame->parent, "distort" ) ) mlt_properties_set( &b_frame->parent, "distort", mlt_properties_get( &a_frame->parent, "distort" ) ); mlt_frame_get_image( a_frame, &p_dest, &format_dest, &width_dest, &height_dest, 1 ); - alpha_dest = mlt_frame_get_alpha_mask( a_frame ); + alpha_dest = mlt_frame_get_alpha( a_frame ); mlt_frame_get_image( b_frame, &p_src, &format_src, &width_src, &height_src, 0 ); - alpha_src = mlt_frame_get_alpha_mask( b_frame ); + alpha_src = mlt_frame_get_alpha( b_frame ); if ( *width == 0 || *height == 0 ) return; diff --git a/src/modules/core/transition_matte.c b/src/modules/core/transition_matte.c index 69c86a37d..187acfd7c 100644 --- a/src/modules/core/transition_matte.c +++ b/src/modules/core/transition_matte.c @@ -180,7 +180,14 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f // Get the image from the a frame mlt_frame_get_image( b_frame, &image_b, format, &width_b, &height_b, 1 ); - alpha_a = mlt_frame_get_alpha_mask( a_frame ); + alpha_a = mlt_frame_get_alpha( a_frame ); + if ( !alpha_a ) + { + int size = width_a * height_a; + alpha_a = mlt_pool_alloc( size ); + memset( alpha_a, 255, size ); + mlt_frame_set_alpha( a_frame, alpha_a, size, mlt_pool_release ); + } // copy data copy_Y_to_A_scaled_luma diff --git a/src/modules/core/transition_region.c b/src/modules/core/transition_region.c deleted file mode 100644 index 739fe0852..000000000 --- a/src/modules/core/transition_region.c +++ /dev/null @@ -1,456 +0,0 @@ -/* - * transition_region.c -- region transition - * Copyright (C) 2003-2017 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 "transition_region.h" -#include "transition_composite.h" - -#include - -#include -#include -#include - -static int create_instance( mlt_transition transition, char *name, char *value, int count ) -{ - // Return from this function - int error = 0; - - // Duplicate the value - char *type = strdup( value ); - - // Pointer to filter argument - char *arg = type == NULL ? NULL : strchr( type, ':' ); - - // New filter being created - mlt_filter filter = NULL; - - // Cleanup type and arg - if ( arg != NULL ) - *arg ++ = '\0'; - - // Create the filter - mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); - if ( type ) - filter = mlt_factory_filter( profile, type, arg ); - - // If we have a filter, then initialise and store it - if ( filter != NULL ) - { - // Properties of transition - mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); - - // String to hold the property name - char id[ 256 ]; - - // String to hold the passdown key - char key[ 256 ]; - - // Construct id - sprintf( id, "_filter_%d", count ); - - // Counstruct key - sprintf( key, "%s.", name ); - - // Just in case, let's assume that the filter here has a composite - //mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "composite.geometry", "0%/0%:100%x100%" ); - //mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "composite.fill", 1 ); - - // Pass all the key properties on the filter down - mlt_properties_pass( MLT_FILTER_PROPERTIES( filter ), properties, key ); - mlt_properties_pass_list( MLT_FILTER_PROPERTIES( filter ), properties, "in, out, length" ); - - // Ensure that filter is assigned - mlt_properties_set_data( properties, id, filter, 0, ( mlt_destructor )mlt_filter_close, NULL ); - } - else - { - // Indicate that an error has occurred - error = 1; - } - - // Cleanup - free( type ); - - // Return error condition - return error; -} - -static uint8_t *filter_get_alpha_mask( mlt_frame frame ) -{ - uint8_t *alpha = NULL; - - // Obtain properties of frame - mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); - - // Get the shape frame - mlt_frame shape_frame = mlt_properties_get_data( properties, "shape_frame", NULL ); - - // Get the width and height of the image - int region_width = mlt_properties_get_int( properties, "width" ); - int region_height = mlt_properties_get_int( properties, "height" ); - uint8_t *image = NULL; - mlt_image_format format = mlt_image_yuv422; - - // Get the shape image to trigger alpha creation - mlt_properties_set_int( MLT_FRAME_PROPERTIES( shape_frame ), "distort", 1 ); - mlt_frame_get_image( shape_frame, &image, &format, ®ion_width, ®ion_height, 0 ); - - alpha = mlt_frame_get_alpha_mask( shape_frame ); - - int size = region_width * region_height; - uint8_t *alpha_duplicate = mlt_pool_alloc( size ); - - // Generate from the Y component of the image if no alpha available - if ( alpha == NULL ) - { - alpha = alpha_duplicate; - while ( size -- ) - { - *alpha ++ = ( int )( ( ( *image ++ - 16 ) * 299 ) / 255 ); - image ++; - } - } - else - { - memcpy( alpha_duplicate, alpha, size ); - } - mlt_frame_set_alpha( frame, alpha_duplicate, region_width * region_height, mlt_pool_release ); - - return alpha_duplicate; -} - -/** Do it :-). -*/ - -static int transition_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) -{ - // Error we will return - int error = 0; - - // We will get the 'b frame' from the frame stack - mlt_frame b_frame = mlt_frame_pop_frame( frame ); - - // Get the watermark transition object - mlt_transition transition = mlt_frame_pop_service( frame ); - - // Get the properties of the transition - mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); - - // Get the properties of the a frame - mlt_properties a_props = MLT_FRAME_PROPERTIES( frame ); - - mlt_service_lock( MLT_TRANSITION_SERVICE( transition ) ); - - // Get the composite from the transition - mlt_transition composite = mlt_properties_get_data( properties, "composite", NULL ); - - // Look for the first filter - mlt_filter filter = mlt_properties_get_data( properties, "_filter_0", NULL ); - - // Get the position - mlt_position position = mlt_transition_get_position( transition, frame ); - - // Create a composite if we don't have one - if ( composite == NULL ) - { - // Create composite via the factory - mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); - composite = mlt_factory_transition( profile, "composite", NULL ); - - // If we have one - if ( composite != NULL ) - { - // Get the properties - mlt_properties composite_properties = MLT_TRANSITION_PROPERTIES( composite ); - - // We want to ensure that we don't get a wobble... - //mlt_properties_set_int( composite_properties, "distort", 1 ); - mlt_properties_set_int( composite_properties, "progressive", 1 ); - - // Pass all the composite. properties on the transition down - mlt_properties_pass( composite_properties, properties, "composite." ); - - // Register the composite for reuse/destruction - mlt_properties_set_data( properties, "composite", composite, 0, ( mlt_destructor )mlt_transition_close, NULL ); - } - } - else - { - // Pass all current properties down - mlt_properties composite_properties = MLT_TRANSITION_PROPERTIES( composite ); - mlt_properties_pass( composite_properties, properties, "composite." ); - } - - // Create filters - if ( filter == NULL ) - { - // Loop Variable - int i = 0; - - // Number of filters created - int count = 0; - - // Loop for all properties - for ( i = 0; i < mlt_properties_count( properties ); i ++ ) - { - // Get the name of this property - char *name = mlt_properties_get_name( properties, i ); - - // If the name does not contain a . and matches filter - if ( strchr( name, '.' ) == NULL && !strncmp( name, "filter", 6 ) ) - { - // Get the filter constructor - char *value = mlt_properties_get_value( properties, i ); - - // Create an instance - if ( create_instance( transition, name, value, count ) == 0 ) - count ++; - } - } - - // Look for the first filter again - filter = mlt_properties_get_data( properties, "_filter_0", NULL ); - } - else - { - // Pass all properties down - mlt_filter temp = NULL; - - // Loop Variable - int i = 0; - - // Number of filters found - int count = 0; - - // Loop for all properties - for ( i = 0; i < mlt_properties_count( properties ); i ++ ) - { - // Get the name of this property - char *name = mlt_properties_get_name( properties, i ); - - // If the name does not contain a . and matches filter - if ( strchr( name, '.' ) == NULL && !strncmp( name, "filter", 6 ) ) - { - // Strings to hold the id and pass down key - char id[ 256 ]; - char key[ 256 ]; - - // Construct id and key - sprintf( id, "_filter_%d", count ); - sprintf( key, "%s.", name ); - - // Get the filter - temp = mlt_properties_get_data( properties, id, NULL ); - - if ( temp != NULL ) - { - mlt_properties_pass( MLT_FILTER_PROPERTIES( temp ), properties, key ); - count ++; - } - } - } - } - - mlt_properties_set_int( a_props, "width", *width ); - mlt_properties_set_int( a_props, "height", *height ); - - // Only continue if we have both filter and composite - if ( composite != NULL ) - { - // Get the resource of this filter (could be a shape [rectangle/circle] or an alpha provider of choice - const char *resource = mlt_properties_get( properties, "resource" ); - - // Get the old resource in case it's changed - char *old_resource = mlt_properties_get( properties, "_old_resource" ); - - // String to hold the filter to query on - char id[ 256 ]; - - // Index to hold the count - int i = 0; - - // We will get the 'b frame' from the composite only if it's NULL (region filter) - if ( b_frame == NULL ) - { - // Copy the region - b_frame = composite_copy_region( composite, frame, position ); - - // Ensure a destructor - char name[64]; - snprintf( name, sizeof(name), "region %s", mlt_properties_get( properties, "_unique_id" ) ); - mlt_properties_set_data( a_props, name, b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); - } - - // Properties of the B frame - mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); - - // filter_only prevents copying the alpha channel of the shape to the output frame - // by compositing filtered frame over itself - if ( mlt_properties_get_int( properties, "filter_only" ) ) - { - char name[64]; - snprintf( name, sizeof(name), "region %s", mlt_properties_get( properties, "_unique_id" ) ); - frame = composite_copy_region( composite, b_frame, position ); - mlt_properties_set_data( b_props, name, frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); - } - - // Make sure the filter is in the correct position - while ( filter != NULL ) - { - // Stack this filter - if ( mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "off" ) == 0 ) - mlt_filter_process( filter, b_frame ); - - // Generate the key for the next - sprintf( id, "_filter_%d", ++ i ); - - // Get the next filter - filter = mlt_properties_get_data( properties, id, NULL ); - } - - // Allow filters to be attached to a region filter - filter = mlt_properties_get_data( properties, "_region_filter", NULL ); - if ( filter != NULL ) - mlt_service_apply_filters( MLT_FILTER_SERVICE( filter ), b_frame, 0 ); - - // Hmm - this is probably going to go wrong.... - mlt_frame_set_position( frame, position ); - - // Get the b frame and process with composite if successful - mlt_transition_process( composite, frame, b_frame ); - - // If we have a shape producer copy the alpha mask from the shape frame to the b_frame - if ( strcmp( resource, "rectangle" ) != 0 ) - { - // Get the producer from the transition - mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); - - // If We have no producer then create one - if ( producer == NULL || ( old_resource != NULL && strcmp( resource, old_resource ) ) ) - { - // Get the factory producer service - char *factory = mlt_properties_get( properties, "factory" ); - - // Store the old resource - mlt_properties_set( properties, "_old_resource", resource ); - - // Special case circle resource - if ( strcmp( resource, "circle" ) == 0 ) - resource = "pixbuf:"; - - // Create the producer - mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); - producer = mlt_factory_producer( profile, factory, resource ); - - // If we have one - if ( producer != NULL ) - { - // Get the producer properties - mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); - - // Ensure that we loop - mlt_properties_set( producer_properties, "eof", "loop" ); - - // Now pass all producer. properties on the transition down - mlt_properties_pass( producer_properties, properties, "producer." ); - - // Register the producer for reuse/destruction - mlt_properties_set_data( properties, "producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); - } - } - - // Now use the shape producer - if ( producer != NULL ) - { - // We will get the alpha frame from the producer - mlt_frame shape_frame = NULL; - - // Make sure the producer is in the correct position - mlt_producer_seek( producer, position ); - - // Get the shape frame - if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &shape_frame, 0 ) == 0 ) - { - // Ensure that the shape frame will be closed - mlt_properties_set_data( b_props, "shape_frame", shape_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); - - // Specify the callback for evaluation - b_frame->get_alpha_mask = filter_get_alpha_mask; - } - } - } - - // Get the image - error = mlt_frame_get_image( frame, image, format, width, height, 0 ); - } - - mlt_service_unlock( MLT_TRANSITION_SERVICE( transition ) ); - - return error; -} - -/** Filter processing. -*/ - -static mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) -{ - // Push the transition on to the frame - mlt_frame_push_service( a_frame, transition ); - - // Push the b_frame on to the stack - mlt_frame_push_frame( a_frame, b_frame ); - - // Push the transition method - mlt_frame_push_get_image( a_frame, transition_get_image ); - - // Return the frame - return a_frame; -} - -/** Constructor for the transition. -*/ - -mlt_transition transition_region_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - // Create a new transition - mlt_transition transition = mlt_transition_new( ); - - // Further initialisation - if ( transition != NULL ) - { - // Get the properties from the transition - mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); - - // Assign the transition process method - transition->process = transition_process; - - // Default factory - mlt_properties_set( properties, "factory", mlt_environment( "MLT_PRODUCER" ) ); - - // Resource defines the shape of the region - mlt_properties_set( properties, "resource", arg == NULL ? "rectangle" : arg ); - - // Inform apps and framework that this is a video only transition - mlt_properties_set_int( properties, "_transition_type", 1 ); - } - - // Return the transition - return transition; -} - diff --git a/src/modules/core/transition_region.yml b/src/modules/core/transition_region.yml deleted file mode 100644 index ab3ff4737..000000000 --- a/src/modules/core/transition_region.yml +++ /dev/null @@ -1,52 +0,0 @@ -schema_version: 0.1 -type: transition -identifier: region -title: Regionalize -version: 1 -copyright: Meltytech, LLC -creator: Charles Yates -license: LGPLv2.1 -language: en -tags: - - Video -description: > - Apply zero or more filters to B frame as it is composited onto a region of - the A frame. The "shape" of the region can be defined by the alpha channel - of a third producer. -parameters: - - identifier: argument - title: Shape producer - type: string - description: > - The default shape is a rectangle, "circle" is a pixbuf-generated SVG - circle, anything else is loaded by the factory. - - identifier: factory - title: Factory - type: string - description: > - The service that creates the shape producer. - default: loader - - identifier: filter[N] - title: Filter - type: string - description: > - One or more filters to apply. All filter properties are passed using the - same filter "key". - - identifier: composite.* - title: Composite - type: properties - service-name: transition.composite - description: > - Properties may be set on the encapsulated composite transition. - - e.g.: composite.valign=c - - See "composite" transition for details. - readonly: no - - identifier: filter_only - title: Use region for filtering only - type: integer - minimum: 0 - maximum: 1 - default: 0 - widget: checkbox diff --git a/src/modules/decklink/CMakeLists.txt b/src/modules/decklink/CMakeLists.txt index f40f4b589..36580f0d6 100644 --- a/src/modules/decklink/CMakeLists.txt +++ b/src/modules/decklink/CMakeLists.txt @@ -3,8 +3,9 @@ add_library(mltdecklink MODULE consumer_decklink.cpp producer_decklink.cpp ) +target_compile_options(mltdecklink PRIVATE ${MLT_COMPILE_OPTIONS}) -target_link_libraries(mltdecklink mlt Threads::Threads) +target_link_libraries(mltdecklink PRIVATE mlt Threads::Threads) if(WIN32) target_sources(mltdecklink PRIVATE win/DeckLinkAPI_i.cpp) @@ -12,18 +13,22 @@ if(WIN32) elseif(APPLE) target_sources(mltdecklink PRIVATE darwin/DeckLinkAPIDispatch.cpp) target_include_directories(mltdecklink PRIVATE darwin) + target_link_libraries(mltdecklink PRIVATE "-framework CoreFoundation") else() target_sources(mltdecklink PRIVATE linux/DeckLinkAPIDispatch.cpp) target_include_directories(mltdecklink PRIVATE linux) endif() -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltdecklink PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +if(CPU_SSE) + target_compile_definitions(mltdecklink PRIVATE USE_SSE) +endif() + +set_target_properties(mltdecklink PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(TARGETS mltdecklink LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +install(TARGETS mltdecklink LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES consumer_decklink.yml producer_decklink.yml - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/decklink + DESTINATION ${MLT_INSTALL_DATA_DIR}/decklink ) diff --git a/src/modules/decklink/consumer_decklink.cpp b/src/modules/decklink/consumer_decklink.cpp index 7a8a4de8f..f2cd0313e 100644 --- a/src/modules/decklink/consumer_decklink.cpp +++ b/src/modules/decklink/consumer_decklink.cpp @@ -1,6 +1,6 @@ /* * consumer_decklink.cpp -- output through Blackmagic Design DeckLink - * Copyright (C) 2010-2018 Meltytech, LLC + * Copyright (C) 2010-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 @@ -512,7 +512,7 @@ class DeckLinkConsumer void renderVideo( mlt_frame frame ) { HRESULT hr; - mlt_image_format format = m_isKeyer? mlt_image_rgb24a : mlt_image_yuv422; + mlt_image_format format = m_isKeyer? mlt_image_rgba : mlt_image_yuv422; uint8_t* image = 0; int rendered = mlt_properties_get_int( MLT_FRAME_PROPERTIES(frame), "rendered"); mlt_properties consumer_properties = MLT_CONSUMER_PROPERTIES( getConsumer() ); @@ -851,7 +851,7 @@ class DeckLinkConsumer render( frame ); mlt_log_timings_end( NULL, "render" ); - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); // terminate on pause if ( m_terminate_on_pause && @@ -929,8 +929,9 @@ static void close( mlt_consumer consumer ) extern "C" { // Listen for the list_devices property to be set -static void on_property_changed( void*, mlt_properties properties, const char *name ) +static void on_property_changed( void*, mlt_properties properties, mlt_event_data event_data ) { + const char *name = mlt_event_data_to_string(event_data); IDeckLinkIterator* decklinkIterator = NULL; IDeckLink* decklink = NULL; IDeckLinkInput* decklinkOutput = NULL; @@ -1017,10 +1018,10 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat const char *service_type = NULL; switch ( type ) { - case consumer_type: + case mlt_service_consumer_type: service_type = "consumer"; break; - case producer_type: + case mlt_service_producer_type: service_type = "producer"; break; default: @@ -1032,10 +1033,10 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( consumer_type, "decklink", consumer_decklink_init ); - MLT_REGISTER( producer_type, "decklink", producer_decklink_init ); - MLT_REGISTER_METADATA( consumer_type, "decklink", metadata, NULL ); - MLT_REGISTER_METADATA( producer_type, "decklink", metadata, NULL ); + MLT_REGISTER( mlt_service_consumer_type, "decklink", consumer_decklink_init ); + MLT_REGISTER( mlt_service_producer_type, "decklink", producer_decklink_init ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "decklink", metadata, NULL ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "decklink", metadata, NULL ); } } // extern C diff --git a/src/modules/decklink/producer_decklink.cpp b/src/modules/decklink/producer_decklink.cpp index 089c05521..10e1287f6 100644 --- a/src/modules/decklink/producer_decklink.cpp +++ b/src/modules/decklink/producer_decklink.cpp @@ -1,6 +1,6 @@ /* * producer_decklink.c -- input from Blackmagic Design DeckLink - * Copyright (C) 2011-2019 Meltytech, LLC + * 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 @@ -793,8 +793,9 @@ static void producer_close( mlt_producer producer ) extern "C" { // Listen for the list_devices property to be set -static void on_property_changed( void*, mlt_properties properties, const char *name ) +static void on_property_changed( void*, mlt_properties properties, mlt_event_data event_data ) { + const char *name = mlt_event_data_to_string(event_data); IDeckLinkIterator* decklinkIterator = NULL; IDeckLink* decklink = NULL; IDeckLinkInput* decklinkInput = NULL; diff --git a/src/modules/dv/Makefile b/src/modules/dv/Makefile deleted file mode 100644 index 4252ef148..000000000 --- a/src/modules/dv/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -CFLAGS += -I../.. - -LDFLAGS += -L../../framework -lmlt -lpthread - -include ../../../config.mak - -TARGET = ../libmltdv$(LIBSUF) - -OBJS = factory.o \ - producer_libdv.o \ - consumer_libdv.o - -CFLAGS += `pkg-config --cflags libdv` - -LDFLAGS += `pkg-config --libs libdv` - -SRCS := $(OBJS:.o=.c) - -all: $(TARGET) - -$(TARGET): $(OBJS) - $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) - -depend: $(SRCS) - $(CC) -MM $(CFLAGS) $^ 1>.depend - -distclean: clean - rm -f .depend - -clean: - rm -f $(OBJS) $(TARGET) - -install: all - install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" - install -d "$(DESTDIR)$(mltdatadir)/dv" - install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/dv" - -ifneq ($(wildcard .depend),) -include .depend -endif diff --git a/src/modules/dv/configure b/src/modules/dv/configure deleted file mode 100755 index 6712ea613..000000000 --- a/src/modules/dv/configure +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -if [ "$help" != "1" ] -then - - pkg-config libdv 2> /dev/null - disable_libdv=$? - - if [ "$disable_libdv" != "0" ] - then - echo "- libdv not found: disabling" - touch ../disable-dv - exit 0 - fi - -fi - diff --git a/src/modules/dv/consumer_libdv.c b/src/modules/dv/consumer_libdv.c deleted file mode 100644 index bef1f1b33..000000000 --- a/src/modules/dv/consumer_libdv.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - * consumer_libdv.c -- a DV encoder based on libdv - * Copyright (C) 2003-2017 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 - */ - -// mlt Header files -#include -#include - -// System header files -#include -#include -#include -#include - -// libdv header files -#include - -#define FRAME_SIZE_525_60 10 * 150 * 80 -#define FRAME_SIZE_625_50 12 * 150 * 80 - -// Forward references. -static int consumer_start( mlt_consumer this ); -static int consumer_stop( mlt_consumer this ); -static int consumer_is_stopped( mlt_consumer this ); -static int consumer_encode_video( mlt_consumer this, uint8_t *dv_frame, mlt_frame frame ); -static void consumer_encode_audio( mlt_consumer this, uint8_t *dv_frame, mlt_frame frame ); -static void consumer_output( mlt_consumer this, uint8_t *dv_frame, int size, mlt_frame frame ); -static void *consumer_thread( void *arg ); -static void consumer_close( mlt_consumer this ); - -/** Initialise the dv consumer. -*/ - -mlt_consumer consumer_libdv_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - // Allocate the consumer - mlt_consumer this = calloc( 1, sizeof( struct mlt_consumer_s ) ); - - // If memory allocated and initialises without error - if ( this != NULL && mlt_consumer_init( this, NULL, profile ) == 0 ) - { - // Get properties from the consumer - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - - // Assign close callback - this->close = consumer_close; - - // Interpret the argument - if ( arg != NULL ) - mlt_properties_set( properties, "target", arg ); - - // Set the encode and output handling method - mlt_properties_set_data( properties, "video", consumer_encode_video, 0, NULL, NULL ); - mlt_properties_set_data( properties, "audio", consumer_encode_audio, 0, NULL, NULL ); - mlt_properties_set_data( properties, "output", consumer_output, 0, NULL, NULL ); - - // Terminate at end of the stream by default - mlt_properties_set_int( properties, "terminate_on_pause", 1 ); - - // Set up start/stop/terminated callbacks - this->start = consumer_start; - this->stop = consumer_stop; - this->is_stopped = consumer_is_stopped; - } - else - { - // Clean up in case of init failure - free( this ); - this = NULL; - } - - // Return this - return this; -} - -/** Start the consumer. -*/ - -static int consumer_start( mlt_consumer this ) -{ - // Get the properties - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - - // Check that we're not already running - if ( !mlt_properties_get_int( properties, "running" ) ) - { - // Allocate a thread - pthread_t *thread = calloc( 1, sizeof( pthread_t ) ); - - // Assign the thread to properties - mlt_properties_set_data( properties, "thread", thread, sizeof( pthread_t ), free, NULL ); - - // Set the running state - mlt_properties_set_int( properties, "running", 1 ); - - // Create the thread - pthread_create( thread, NULL, consumer_thread, this ); - } - return 0; -} - -/** Stop the consumer. -*/ - -static int consumer_stop( mlt_consumer this ) -{ - // Get the properties - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - - // Check that we're running - if ( mlt_properties_get_int( properties, "running" ) ) - { - // Get the thread - pthread_t *thread = mlt_properties_get_data( properties, "thread", NULL ); - - // Stop the thread - mlt_properties_set_int( properties, "running", 0 ); - - // Wait for termination - pthread_join( *thread, NULL ); - - // Close the output file :-) - this is obtuse - doesn't matter if output file - // exists or not - the destructor will kick in if it does - mlt_properties_set_data( properties, "output_file", NULL, 0, NULL, NULL ); - } - - return 0; -} - -/** Determine if the consumer is stopped. -*/ - -static int consumer_is_stopped( mlt_consumer this ) -{ - // Get the properties - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - return !mlt_properties_get_int( properties, "running" ); -} - -/** Get or create a new libdv encoder. -*/ - -static dv_encoder_t *libdv_get_encoder( mlt_consumer this, mlt_frame frame ) -{ - // Get the properties of the consumer - mlt_properties this_properties = MLT_CONSUMER_PROPERTIES( this ); - - // Obtain the dv_encoder - dv_encoder_t *encoder = mlt_properties_get_data( this_properties, "dv_encoder", NULL ); - - // Construct one if we don't have one - if ( encoder == NULL ) - { - // Get the fps of the consumer (for now - should be from frame) - double fps = mlt_properties_get_double( this_properties, "fps" ); - - // Create the encoder - encoder = dv_encoder_new( 0, 0, 0 ); - - // Encoder settings - encoder->isPAL = fps == 25; - encoder->is16x9 = 0; - encoder->vlc_encode_passes = 1; - encoder->static_qno = 0; - encoder->force_dct = DV_DCT_AUTO; - - // Store the encoder on the properties - mlt_properties_set_data( this_properties, "dv_encoder", encoder, 0, ( mlt_destructor )dv_encoder_free, NULL ); - } - - // Return the encoder - return encoder; -} - - -/** The libdv encode video method. -*/ - -static int consumer_encode_video( mlt_consumer this, uint8_t *dv_frame, mlt_frame frame ) -{ - // Obtain the dv_encoder - dv_encoder_t *encoder = libdv_get_encoder( this, frame ); - - // Get the properties of the consumer - mlt_properties this_properties = MLT_CONSUMER_PROPERTIES( this ); - - // This will hold the size of the dv frame - int size = 0; - - // Is the image rendered - int rendered = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "rendered" ); - - // Get width and height - int width = mlt_properties_get_int( this_properties, "width" ); - int height = mlt_properties_get_int( this_properties, "height" ); - - // If we get an encoder, then encode the image - if ( rendered && encoder != NULL ) - { - // Specify desired image properties - mlt_image_format fmt = mlt_image_yuv422; - uint8_t *image = NULL; - - // Get the image - mlt_frame_get_image( frame, &image, &fmt, &width, &height, 0 ); - - // Check that we get what we expected - if ( fmt != mlt_image_yuv422 || - width != mlt_properties_get_int( this_properties, "width" ) || - height != mlt_properties_get_int( this_properties, "height" ) || - image == NULL ) - { - // We should try to recover here - fprintf( stderr, "We have a problem houston...\n" ); - } - else - { - // Calculate the size of the dv frame - size = height == 576 ? FRAME_SIZE_625_50 : FRAME_SIZE_525_60; - } - - // Process the frame - if ( size != 0 ) - { - // Encode the image - dv_encode_full_frame( encoder, &image, e_dv_color_yuv, dv_frame ); - } - mlt_events_fire( this_properties, "consumer-frame-show", frame, NULL ); - } - else if ( encoder != NULL ) - { - // Calculate the size of the dv frame (duplicate of previous) - size = height == 576 ? FRAME_SIZE_625_50 : FRAME_SIZE_525_60; - } - - return size; -} - -/** The libdv encode audio method. -*/ - -static void consumer_encode_audio( mlt_consumer this, uint8_t *dv_frame, mlt_frame frame ) -{ - // Get the properties of the consumer - mlt_properties this_properties = MLT_CONSUMER_PROPERTIES( this ); - - // Get the properties of the frame - mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); - - // Obtain the dv_encoder - dv_encoder_t *encoder = libdv_get_encoder( this, frame ); - - // Only continue if we have an encoder - if ( encoder != NULL ) - { - // Get the frame count - int count = mlt_properties_get_int( this_properties, "count" ); - - // Default audio args - mlt_audio_format fmt = mlt_audio_s16; - int channels = 2; - int frequency = mlt_properties_get_int( this_properties, "frequency" ); - int samples = mlt_audio_calculate_frame_samples( mlt_properties_get_double( this_properties, "fps" ), frequency, count ); - int16_t *pcm = NULL; - - // Get the frame number - time_t start = time( NULL ); - int height = mlt_properties_get_int( this_properties, "height" ); - int is_pal = height == 576; - int is_wide = mlt_properties_get_int( this_properties, "display_aspect_num" ) == 16; - - // Temporary - audio buffer allocation - int16_t *audio_buffers[ 4 ]; - int i = 0; - int j = 0; - for ( i = 0 ; i < 4; i ++ ) - audio_buffers[ i ] = mlt_pool_alloc( 2 * DV_AUDIO_MAX_SAMPLES ); - - // Get the audio - mlt_frame_get_audio( frame, (void**) &pcm, &fmt, &frequency, &channels, &samples ); - - // Inform the encoder of the number of audio samples - encoder->samples_this_frame = samples; - - // Fill the audio buffers correctly - if ( mlt_properties_get_double( frame_properties, "_speed" ) == 1.0 ) - { - for ( i = 0; i < samples; i ++ ) - for ( j = 0; j < channels; j++ ) - audio_buffers[ j ][ i ] = *pcm ++; - } - else - { - for ( j = 0; j < channels; j++ ) - memset( audio_buffers[ j ], 0, 2 * DV_AUDIO_MAX_SAMPLES ); - } - - // Encode audio on frame - dv_encode_full_audio( encoder, audio_buffers, channels, frequency, dv_frame ); - - // Specify meta data on the frame - dv_encode_metadata( dv_frame, is_pal, is_wide, &start, count ); - dv_encode_timecode( dv_frame, is_pal, count ); - - // Update properties - mlt_properties_set_int( this_properties, "count", ++ count ); - - // Temporary - free audio buffers - for ( i = 0 ; i < 4; i ++ ) - mlt_pool_release( audio_buffers[ i ] ); - } -} - -/** The libdv output method. -*/ - -static void consumer_output( mlt_consumer this, uint8_t *dv_frame, int size, mlt_frame frame ) -{ - // Get the properties - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - - FILE *output = stdout; - char *target = mlt_properties_get( properties, "target" ); - - if ( target != NULL ) - { - output = mlt_properties_get_data( properties, "output_file", NULL ); - if ( output == NULL ) - { - output = mlt_fopen( target, "wb" ); - if ( output != NULL ) - mlt_properties_set_data( properties, "output_file", output, 0, ( mlt_destructor )fclose, 0 ); - } - } - - if ( output != NULL ) - { - fwrite( dv_frame, size, 1, output ); - fflush( output ); - } - else - { - fprintf( stderr, "Unable to open %s\n", target ); - } -} - -/** The main thread - the argument is simply the consumer. -*/ - -static void *consumer_thread( void *arg ) -{ - // Map the argument to the object - mlt_consumer this = arg; - - // Get the properties - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - - // Get the terminate_on_pause property - int top = mlt_properties_get_int( properties, "terminate_on_pause" ); - - // Get the handling methods - int ( *video )( mlt_consumer, uint8_t *, mlt_frame ) = mlt_properties_get_data( properties, "video", NULL ); - int ( *audio )( mlt_consumer, uint8_t *, mlt_frame ) = mlt_properties_get_data( properties, "audio", NULL ); - int ( *output )( mlt_consumer, uint8_t *, int, mlt_frame ) = mlt_properties_get_data( properties, "output", NULL ); - - // Allocate a single PAL frame for encoding - uint8_t *dv_frame = mlt_pool_alloc( FRAME_SIZE_625_50 ); - - // Frame and size - mlt_frame frame = NULL; - int size = 0; - - // Loop while running - while( mlt_properties_get_int( properties, "running" ) ) - { - // Get the frame - frame = mlt_consumer_rt_frame( this ); - - // Check that we have a frame to work with - if ( frame != NULL ) - { - // Terminate on pause - if ( top && mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0 ) - { - mlt_frame_close( frame ); - break; - } - - // Obtain the dv_encoder - if ( libdv_get_encoder( this, frame ) != NULL ) - { - // Encode the image - size = video( this, dv_frame, frame ); - - // Encode the audio - if ( size > 0 ) - audio( this, dv_frame, frame ); - - // Output the frame - output( this, dv_frame, size, frame ); - - // Close the frame - mlt_frame_close( frame ); - } - else - { - fprintf( stderr, "Unable to obtain dv encoder.\n" ); - } - } - } - - // Tidy up - mlt_pool_release( dv_frame ); - - mlt_consumer_stopped( this ); - - return NULL; -} - -/** Close the consumer. -*/ - -static void consumer_close( mlt_consumer this ) -{ - // Stop the consumer - mlt_consumer_stop( this ); - - // Close the parent - mlt_consumer_close( this ); - - // Free the memory - free( this ); -} diff --git a/src/modules/dv/consumer_libdv.yml b/src/modules/dv/consumer_libdv.yml deleted file mode 100644 index c00bd8547..000000000 --- a/src/modules/dv/consumer_libdv.yml +++ /dev/null @@ -1,21 +0,0 @@ -schema_version: 0.1 -type: consumer -identifier: libdv -title: libdv (*deprecated*) -version: 1 -copyright: Meltytech, LLC -creator: Charles Yates -license: LGPLv2.1 -language: en -tags: - - Audio - - Video -description: > - DV consumer using libdv. -parameters: - - identifier: argument - title: File - type: string - description: The filename to write to, e.g. /dev/dv1394. - required: yes - widget: filesave diff --git a/src/modules/dv/deprecated b/src/modules/dv/deprecated deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/modules/dv/factory.c b/src/modules/dv/factory.c deleted file mode 100644 index f3befb7db..000000000 --- a/src/modules/dv/factory.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * factory.c -- the factory method interfaces - * Copyright (C) 2003-2014 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 - -extern mlt_consumer consumer_libdv_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -extern mlt_producer producer_libdv_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/dv/%s", mlt_environment( "MLT_DATA" ), (char*) data ); - return mlt_properties_parse_yaml( file ); -} - -MLT_REPOSITORY -{ - MLT_REGISTER( consumer_type, "libdv", consumer_libdv_init ); - MLT_REGISTER( producer_type, "libdv", producer_libdv_init ); - - MLT_REGISTER_METADATA( consumer_type, "libdv", metadata, "consumer_libdv.yml" ); - MLT_REGISTER_METADATA( producer_type, "libdv", metadata, "producer_libdv.yml" ); -} diff --git a/src/modules/dv/producer_libdv.c b/src/modules/dv/producer_libdv.c deleted file mode 100644 index c19a521b5..000000000 --- a/src/modules/dv/producer_libdv.c +++ /dev/null @@ -1,566 +0,0 @@ -/* - * producer_libdv.c -- simple libdv test case - * Copyright (C) 2003-2014 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 -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define FRAME_SIZE_525_60 10 * 150 * 80 -#define FRAME_SIZE_625_50 12 * 150 * 80 - -/** To conserve resources, we maintain a stack of dv decoders. -*/ - -static pthread_mutex_t decoder_lock = PTHREAD_MUTEX_INITIALIZER; -static mlt_properties dv_decoders = NULL; - -dv_decoder_t *dv_decoder_alloc( ) -{ - // We'll return a dv_decoder - dv_decoder_t *this = NULL; - - // Lock the mutex - pthread_mutex_lock( &decoder_lock ); - - // Create the properties if necessary - if ( dv_decoders == NULL ) - { - // Create the properties - dv_decoders = mlt_properties_new( ); - - // Create the stack - mlt_properties_set_data( dv_decoders, "stack", mlt_deque_init( ), 0, ( mlt_destructor )mlt_deque_close, NULL ); - - // Register the properties for clean up - mlt_factory_register_for_clean_up( dv_decoders, ( mlt_destructor )mlt_properties_close ); - } - - // Now try to obtain a decoder - if ( dv_decoders != NULL ) - { - // Obtain the stack - mlt_deque stack = mlt_properties_get_data( dv_decoders, "stack", NULL ); - - // Pop the top of the stack - this = mlt_deque_pop_back( stack ); - - // Create a new decoder if none available - if ( this == NULL ) - { - // We'll need a unique property ID for this - char label[ 256 ]; - - // Configure the decoder - this = dv_decoder_new( FALSE, FALSE, FALSE ); - this->quality = DV_QUALITY_COLOR | DV_QUALITY_AC_2; - this->audio->arg_audio_emphasis = 2; - dv_set_audio_correction( this, DV_AUDIO_CORRECT_AVERAGE ); - dv_set_error_log( this, NULL ); - - // Register it with the properties to ensure clean up - sprintf( label, "%p", this ); - mlt_properties_set_data( dv_decoders, label, this, 0, ( mlt_destructor )dv_decoder_free, NULL ); - } - } - - // Unlock the mutex - pthread_mutex_unlock( &decoder_lock ); - - return this; -} - -void dv_decoder_return( dv_decoder_t *this ) -{ - // Lock the mutex - pthread_mutex_lock( &decoder_lock ); - - // Now try to return the decoder - if ( dv_decoders != NULL ) - { - // Obtain the stack - mlt_deque stack = mlt_properties_get_data( dv_decoders, "stack", NULL ); - - // Push it back - mlt_deque_push_back( stack, this ); - } - - // Unlock the mutex - pthread_mutex_unlock( &decoder_lock ); -} - - -typedef struct producer_libdv_s *producer_libdv; - -struct producer_libdv_s -{ - struct mlt_producer_s parent; - int fd; - int is_pal; - uint64_t file_size; - int frame_size; - long frames_in_file; - mlt_producer alternative; -}; - -static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); -static void producer_close( mlt_producer parent ); - -static int producer_collect_info( producer_libdv this, mlt_profile profile ); - -mlt_producer producer_libdv_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename ) -{ - producer_libdv this = calloc( 1, sizeof( struct producer_libdv_s ) ); - - if ( filename != NULL && this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) - { - int destroy = 0; - mlt_producer producer = &this->parent; - mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); - - // Set the resource property (required for all producers) - mlt_properties_set( properties, "resource", filename ); - - // Register transport implementation with the producer - producer->close = ( mlt_destructor )producer_close; - - // Register our get_frame implementation with the producer - producer->get_frame = producer_get_frame; - - // If we have mov or dv, then we'll use an alternative producer - if ( strchr( filename, '.' ) != NULL && ( - strncasecmp( strrchr( filename, '.' ), ".avi", 4 ) == 0 || - strncasecmp( strrchr( filename, '.' ), ".mov", 4 ) == 0 ) ) - { - // Load via an alternative mechanism - mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); - this->alternative = mlt_factory_producer( profile, "kino", filename ); - - // If it's unavailable, then clean up - if ( this->alternative == NULL ) - destroy = 1; - else - mlt_properties_pass( properties, MLT_PRODUCER_PROPERTIES( this->alternative ), "" ); - this->is_pal = ( ( int ) mlt_producer_get_fps( producer ) ) == 25; - } - else - { - // Open the file if specified - this->fd = open( filename, O_RDONLY ); - - // Collect info - if ( this->fd == -1 || !producer_collect_info( this, profile ) ) - destroy = 1; - } - - // If we couldn't open the file, then destroy it now - if ( destroy ) - { - mlt_producer_close( producer ); - producer = NULL; - } - - // Return the producer - return producer; - } - free( this ); - return NULL; -} - -static int read_frame( int fd, uint8_t* frame_buf, int *isPAL ) -{ - int result = read( fd, frame_buf, FRAME_SIZE_525_60 ) == FRAME_SIZE_525_60; - if ( result ) - { - *isPAL = ( frame_buf[3] & 0x80 ); - if ( *isPAL ) - { - int diff = FRAME_SIZE_625_50 - FRAME_SIZE_525_60; - result = read( fd, frame_buf + FRAME_SIZE_525_60, diff ) == diff; - } - } - - return result; -} - -static int producer_collect_info( producer_libdv this, mlt_profile profile ) -{ - int valid = 0; - - uint8_t *dv_data = mlt_pool_alloc( FRAME_SIZE_625_50 ); - - if ( dv_data != NULL ) - { - // Read the first frame - valid = read_frame( this->fd, dv_data, &this->is_pal ); - - // If it looks like a valid frame, the get stats - if ( valid ) - { - double aspect_ratio; - - // Get the properties - mlt_properties properties = MLT_PRODUCER_PROPERTIES( &this->parent ); - - // Get a dv_decoder - dv_decoder_t *dv_decoder = dv_decoder_alloc( ); - - // Determine the file size - struct stat buf; - fstat( this->fd, &buf ); - - // Store the file size - this->file_size = buf.st_size; - - // Determine the frame size - this->frame_size = this->is_pal ? FRAME_SIZE_625_50 : FRAME_SIZE_525_60; - - // Determine the number of frames in the file - this->frames_in_file = this->file_size / this->frame_size; - - // Calculate default in/out points - int fps = 1000 * ( this->is_pal ? 25 : ( 30000.0 / 1001.0 ) ); - if ( ( int )( mlt_profile_fps( profile ) * 1000 ) == fps ) - { - if ( this->frames_in_file > 0 ) - { - mlt_properties_set_position( properties, "length", this->frames_in_file ); - mlt_properties_set_position( properties, "in", 0 ); - mlt_properties_set_position( properties, "out", this->frames_in_file - 1 ); - } - } - else - { - valid = 0; - } - - // Parse the header for meta info - dv_parse_header( dv_decoder, dv_data ); - if ( this->is_pal ) - { - if ( dv_format_wide( dv_decoder ) ) - aspect_ratio = 64.0 / 45.0; - else - aspect_ratio = 16.0 / 15.0; - } - else - { - if ( dv_format_wide( dv_decoder ) ) - aspect_ratio = 32.0 / 27.0; - else - aspect_ratio = 8 / 9; - } - mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio); - mlt_properties_set_int( properties, "meta.media.nb_streams", 2 ); - mlt_properties_set_int( properties, "video_index", 0 ); - mlt_properties_set( properties, "meta.media.0.stream.type", "video" ); - mlt_properties_set( properties, "meta.media.0.codec.name", "dvvideo" ); - mlt_properties_set( properties, "meta.media.0.codec.long_name", "DV (Digital Video)" ); - mlt_properties_set_int( properties, "audio_index", 1 ); - mlt_properties_set( properties, "meta.media.1.stream.type", "audio" ); - mlt_properties_set( properties, "meta.media.1.codec.name", "pcm_s16le" ); - mlt_properties_set( properties, "meta.media.1.codec.long_name", "signed 16-bit little-endian PCM" ); - mlt_properties_set_int( properties, "meta.media.width", 720 ); - mlt_properties_set_int( properties, "meta.media.height", this->is_pal ? 576 : 480 ); - mlt_properties_set_int( properties, "meta.media.frame_rate_num", this->is_pal? 25 : 30000 ); - mlt_properties_set_int( properties, "meta.media.frame_rate_den", this->is_pal? 1 : 1001 ); - - // Return the decoder - dv_decoder_return( dv_decoder ); - } - - mlt_pool_release( dv_data ); - } - - return valid; -} - -static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) -{ - int pitches[3] = { 0, 0, 0 }; - uint8_t *pixels[3] = { NULL, NULL, NULL }; - - // Get the frames properties - mlt_properties properties = MLT_FRAME_PROPERTIES( this ); - - // Get a dv_decoder - dv_decoder_t *decoder = dv_decoder_alloc( ); - - // Get the dv data - uint8_t *dv_data = mlt_properties_get_data( properties, "dv_data", NULL ); - - // Get and set the quality request - char *quality = mlt_frame_pop_service( this ); - - if ( quality != NULL ) - { - if ( strncmp( quality, "fast", 4 ) == 0 ) - decoder->quality = ( DV_QUALITY_COLOR | DV_QUALITY_DC ); - else if ( strncmp( quality, "best", 4 ) == 0 ) - decoder->quality = ( DV_QUALITY_COLOR | DV_QUALITY_AC_2 ); - else - decoder->quality = ( DV_QUALITY_COLOR | DV_QUALITY_AC_1 ); - } - - // Parse the header for meta info - dv_parse_header( decoder, dv_data ); - - // Assign width and height according to the frame - *width = 720; - *height = dv_data[ 3 ] & 0x80 ? 576 : 480; - - // Extract an image of the format requested - if ( *format != mlt_image_rgb24 ) - { - // Allocate an image - uint8_t *image = mlt_pool_alloc( *width * ( *height + 1 ) * 2 ); - - // Pass to properties for clean up - mlt_frame_set_image( this, image, *width * ( *height + 1 ) * 2, mlt_pool_release ); - - // Decode the image - pitches[ 0 ] = *width * 2; - pixels[ 0 ] = image; - dv_decode_full_frame( decoder, dv_data, e_dv_color_yuv, pixels, pitches ); - - // Assign result - *buffer = image; - *format = mlt_image_yuv422; - } - else - { - // Allocate an image - uint8_t *image = mlt_pool_alloc( *width * ( *height + 1 ) * 3 ); - - // Pass to properties for clean up - mlt_frame_set_image( this, image, *width * ( *height + 1 ) * 3, mlt_pool_release ); - - // Decode the frame - pitches[ 0 ] = 720 * 3; - pixels[ 0 ] = image; - dv_decode_full_frame( decoder, dv_data, e_dv_color_rgb, pixels, pitches ); - - // Assign result - *buffer = image; - *format = mlt_image_rgb24; - } - - // Return the decoder - dv_decoder_return( decoder ); - - return 0; -} - -static int producer_get_audio( mlt_frame this, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) -{ - int16_t *p; - int i, j; - int16_t *audio_channels[ 4 ]; - - // Get the frames properties - mlt_properties properties = MLT_FRAME_PROPERTIES( this ); - - // Get a dv_decoder - dv_decoder_t *decoder = dv_decoder_alloc( ); - - // Get the dv data - uint8_t *dv_data = mlt_properties_get_data( properties, "dv_data", NULL ); - - // Parse the header for meta info - dv_parse_header( decoder, dv_data ); - - // Check that we have audio - if ( decoder->audio->num_channels > 0 ) - { - int size = *channels * DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ); - - // Obtain required values - *frequency = decoder->audio->frequency; - *samples = decoder->audio->samples_this_frame; - *channels = decoder->audio->num_channels; - *format = mlt_audio_s16; - - // Create a temporary workspace - for ( i = 0; i < 4; i++ ) - audio_channels[ i ] = mlt_pool_alloc( DV_AUDIO_MAX_SAMPLES * sizeof( int16_t ) ); - - // Create a workspace for the result - *buffer = mlt_pool_alloc( size ); - - // Pass the allocated audio buffer as a property - mlt_frame_set_audio( this, *buffer, *format, size, mlt_pool_release ); - - // Decode the audio - dv_decode_full_audio( decoder, dv_data, audio_channels ); - - // Interleave the audio - p = *buffer; - for ( i = 0; i < *samples; i++ ) - for ( j = 0; j < *channels; j++ ) - *p++ = audio_channels[ j ][ i ]; - - // Free the temporary work space - for ( i = 0; i < 4; i++ ) - mlt_pool_release( audio_channels[ i ] ); - } - else - { - // No audio available on the frame, so get test audio (silence) - mlt_frame_get_audio( this, buffer, format, frequency, channels, samples ); - } - - // Return the decoder - dv_decoder_return( decoder ); - - return 0; -} - -static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) -{ - // Access the private data - producer_libdv this = producer->child; - - // Will carry the frame data - uint8_t *data = NULL; - - // Obtain the current frame number - uint64_t position = mlt_producer_frame( producer ); - - if ( this->alternative == NULL ) - { - // Convert timecode to a file position (ensuring that we're on a frame boundary) - uint64_t offset = position * this->frame_size; - - // Allocate space - data = mlt_pool_alloc( FRAME_SIZE_625_50 ); - - // Create an empty frame - *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); - - // Seek and fetch - if ( this->fd != 0 && - lseek( this->fd, offset, SEEK_SET ) == offset && - read_frame( this->fd, data, &this->is_pal ) ) - { - // Pass the dv data - mlt_properties_set_data( MLT_FRAME_PROPERTIES( *frame ), "dv_data", data, FRAME_SIZE_625_50, ( mlt_destructor )mlt_pool_release, NULL ); - } - else - { - mlt_pool_release( data ); - data = NULL; - } - } - else - { - // Seek - mlt_producer_seek( this->alternative, position ); - - // Fetch - mlt_service_get_frame( MLT_PRODUCER_SERVICE( this->alternative ), frame, 0 ); - - // Verify - if ( *frame != NULL ) - data = mlt_properties_get_data( MLT_FRAME_PROPERTIES( *frame ), "dv_data", NULL ); - } - - if ( data != NULL ) - { - // Get the frames properties - mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); - - // Get a dv_decoder - dv_decoder_t *dv_decoder = dv_decoder_alloc( ); - - mlt_properties_set_int( properties, "test_image", 0 ); - mlt_properties_set_int( properties, "test_audio", 0 ); - - // Update other info on the frame - mlt_properties_set_int( properties, "width", 720 ); - mlt_properties_set_int( properties, "height", this->is_pal ? 576 : 480 ); - mlt_properties_set_int( properties, "top_field_first", !this->is_pal ? 0 : ( data[ 5 ] & 0x07 ) == 0 ? 0 : 1 ); - mlt_properties_set_int( properties, "colorspace", 601 ); - - // Parse the header for meta info - dv_parse_header( dv_decoder, data ); - //mlt_properties_set_int( properties, "progressive", dv_is_progressive( dv_decoder ) ); - mlt_properties_set_double( properties, "aspect_ratio", - dv_format_wide( dv_decoder ) ? ( this->is_pal ? 118.0/81.0 : 40.0/33.0 ) : ( this->is_pal ? 59.0/54.0 : 10.0/11.0 ) ); - - - mlt_properties_set_int( properties, "audio_frequency", dv_decoder->audio->frequency ); - mlt_properties_set_int( properties, "audio_channels", dv_decoder->audio->num_channels ); - - // Register audio callback - if ( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( producer ), "audio_index" ) > 0 ) - mlt_frame_push_audio( *frame, producer_get_audio ); - - if ( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( producer ), "video_index" ) > -1 ) - { - // Push the quality string - mlt_frame_push_service( *frame, mlt_properties_get( MLT_PRODUCER_PROPERTIES( producer ), "quality" ) ); - - // Push the get_image method on to the stack - mlt_frame_push_get_image( *frame, producer_get_image ); - } - - // Return the decoder - dv_decoder_return( dv_decoder ); - } - - // Update timecode on the frame we're creating - if ( *frame != NULL ) - mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); - - // Calculate the next timecode - mlt_producer_prepare_next( producer ); - - return 0; -} - -static void producer_close( mlt_producer parent ) -{ - // Obtain this - producer_libdv this = parent->child; - - // Close the file - if ( this->fd > 0 ) - close( this->fd ); - - if ( this->alternative ) - mlt_producer_close( this->alternative ); - - // Close the parent - parent->close = NULL; - mlt_producer_close( parent ); - - // Free the memory - free( this ); -} diff --git a/src/modules/dv/producer_libdv.yml b/src/modules/dv/producer_libdv.yml deleted file mode 100644 index a085a2737..000000000 --- a/src/modules/dv/producer_libdv.yml +++ /dev/null @@ -1,29 +0,0 @@ -schema_version: 0.1 -type: producer -identifier: libdv -title: libdv (*deprecated*) -version: 1 -copyright: Meltytech, LLC -creator: Charles Yates -license: LGPLv2.1 -language: en -tags: - - Audio - - Video -description: A libdv based decoder for video and audio. -parameters: - - identifier: argument - title: File - type: string - required: yes - readonly: no - widget: fileopen - - - identifier: quality - title: Quality - type: string - description: One of "best," "fast" or anything else chooses medium. - readonly: no - mutable: yes - widget: combo - default: best diff --git a/src/modules/feeds/CMakeLists.txt b/src/modules/feeds/CMakeLists.txt deleted file mode 100644 index 7d9af45d7..000000000 --- a/src/modules/feeds/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -install(FILES - NTSC/data_fx.properties - NTSC/etv.properties - NTSC/obscure.properties - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/feeds/NTSC -) - -install(FILES - PAL/border.properties - PAL/data_fx.properties - PAL/etv.properties - PAL/example.properties - PAL/obscure.properties - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/feeds/PAL -) diff --git a/src/modules/feeds/Makefile b/src/modules/feeds/Makefile deleted file mode 100644 index 45bd7aed2..000000000 --- a/src/modules/feeds/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -include ../../../config.mak - -all: - -depend: - -distclean: - -clean: - -install: all - install -d "$(DESTDIR)$(mltdatadir)/feeds/PAL" - install -d "$(DESTDIR)$(mltdatadir)/feeds/NTSC" - install -m 644 PAL/*.* "$(DESTDIR)$(mltdatadir)/feeds/PAL" - install -m 644 NTSC/*.* "$(DESTDIR)$(mltdatadir)/feeds/NTSC" diff --git a/src/modules/feeds/NTSC/data_fx.properties b/src/modules/feeds/NTSC/data_fx.properties deleted file mode 100644 index fced7929a..000000000 --- a/src/modules/feeds/NTSC/data_fx.properties +++ /dev/null @@ -1,82 +0,0 @@ -# This properties file describes the fx available to the data_feed and -# data_show filters -# -# Syntax is as follows: -# -# name= -# name.description= -# name.properties.= -# name.=value -# etc -# -# Typically, the is a 'region' and additional filters are -# included as properties using the normal region filter syntax. -# - -# -# The titles filter definition -# - -titles=region -.description=Titles -.properties.markup=filter[1].producer.markup -.type.markup=text -.period=2 -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.composite.geometry=5%/70%:90%x20% -.filter[0]=watermark -.filter[0].resource=colour:0x000000ff -.filter[0].composite.geometry=0%/0%:100%x100%:0;5=0%/0%:100%x100%:40 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=Shotcut -.filter[1].composite.geometry=0%/0%:100%x100%:0;8=0%/0%:100%x100%:100 -.filter[1].composite.titles=1 - -# -# The top titles filter definition -# - -top-titles=region -.description=Top Titles -.properties.markup=filter[1].producer.markup -.type.markup=text -.period=2 -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.composite.geometry=5%/5%:90%x20% -.filter[0]=watermark -.filter[0].resource=colour:0x000000ff -.filter[0].composite.geometry=0%/0%:100%x100%:0;5=0%/0%:100%x100%:40 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=Shotcut -.filter[1].composite.geometry=0%/0%:100%x100%:0;8=0%/0%:100%x100%:100 -.filter[1].composite.halign=centre -.filter[1].composite.titles=1 - -# -# OK - Silly example... -# - -tickertape=region -.description=Tickertape -.properties.markup=filter[1].producer.markup -.type.markup=text -.properties.length[0]=filter[1].composite.out -.composite.geometry=0%/93%:100%x7% -.filter[0]=watermark -.filter[0].resource=colour:0x000000ff -.filter[0].composite.geometry=0%/0%:100%x100%:100 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=Shotcut -.filter[1].composite.geometry=100%/0%:300%x100%:100;-1=-300%/0%:300%x100%:100 -.filter[1].producer.family=San -.filter[1].producer.size=32 -.filter[1].composite.titles=1 - diff --git a/src/modules/feeds/NTSC/etv.properties b/src/modules/feeds/NTSC/etv.properties deleted file mode 100644 index 421a48506..000000000 --- a/src/modules/feeds/NTSC/etv.properties +++ /dev/null @@ -1,186 +0,0 @@ -# This properties file describes the fx available to the data_feed and -# data_show filters -# -# Syntax is as follows: -# -# name= -# name.description= -# name.properties.= -# name.=value -# etc -# -# Typically, the is a 'region' and additional filters are -# included as properties using the normal region filter syntax. -# - -location=region -.description=Titles -.properties.markup=filter[1].producer.text -.properties.family=filter[1].producer.family -.properties.size=filter[1].producer.size -.period=2 -.properties.length[0]=composite.out -.composite.geometry=0/14%:32%x5%:0;15=/:x:100 -.composite.luma=%luma01.pgm -.composite.softness=.3 -.filter[0]=watermark -.filter[0].resource=colour:0x6c0101ff -.filter[0].composite.distort=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text= -.filter[1].producer.family=Sans -.filter[1].producer.size=24 -.filter[1].composite.geometry=0/0:95%x100% -.filter[1].composite.titles=1 -.filter[1].composite.halign=right -.filter[1].composite.valign=center - -courtesy=region -.description=Courtesy -.properties.markup=filter[1].producer.text -.properties.family=filter[1].producer.family -.properties.size=filter[1].producer.size -.period=2 -.properties.length[0]=composite.out -.composite.geometry=0/20%:32%x5%:0;15=/:x:100 -.composite.luma=%luma01.pgm -.composite.softness=.3 -.filter[0]=watermark -.filter[0].resource=colour:0x6c0101ff -.filter[0].composite.distort=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text= -.filter[1].producer.family=Sans -.filter[1].producer.size=24 -.filter[1].composite.geometry=0/0:95%x100% -.filter[1].composite.titles=1 -.filter[1].composite.halign=right -.filter[1].composite.valign=centre - -exclusive=region -.description=Exclusive -.properties.markup=filter[1].producer.text -.properties.family=filter[1].producer.family -.properties.size=filter[1].producer.size -.period=2 -.properties.length[0]=composite.out -.composite.geometry=-32%/20%:32%x5%;15=0 -.filter[0]=watermark -.filter[0].resource=colour:0x6c0101ff -.filter[0].composite.distort=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text=ETV Exclusive -.filter[1].producer.family=Sans -.filter[1].producer.size=24 -.filter[1].producer.weight=700 -.filter[1].composite.geometry=0/0:95%x100% -.filter[1].composite.titles=1 -.filter[1].composite.halign=right -.filter[1].composite.valign=centre - -file_shot=region -.description=Titles -.period=2 -.properties.family=filter[1].producer.family -.properties.size=filter[1].producer.size -.properties.length[0]=composite.out -.composite.geometry=82%/28%:11%x4%:0;15=/:x:100 -.filter[0]=watermark -.filter[0].resource=colour:0x6c0101ff -.filter[0].composite.distort=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text=File Shot -.filter[1].producer.family=Sans -.filter[1].producer.size=18 -.filter[1].producer.weight=700 -.filter[1].composite.titles=1 -.filter[1].composite.halign=centre -.filter[1].composite.valign=centre - -special=region -.description=Special -.period=2 -.properties.family=filter[1].producer.family -.properties.size=filter[1].producer.size -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.composite.geometry=65%/65%:35%x6% -.filter[0]=watermark -.filter[0].resource=colour:0x6c0101ff -.filter[0].composite.geometry=100%/0%:100%x100%:0;15=0%/0%:x:100 -.filter[0].composite.distort=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text=Special -.filter[1].producer.family=Sans -.filter[1].producer.size=24 -.filter[1].producer.weight=700 -.filter[1].composite.geometry=100%/0%:100%x100%:0;15=0%/0%:x:100 -.filter[1].composite.titles=1 -.filter[1].composite.halign=centre -.filter[1].composite.valign=centre - -ticker=region -.description=Tickertape -.properties.markup=filter[1].producer.text -.properties.family=filter[1].producer.family -.properties.size=filter[1].producer.size -.properties.length[0]=filter[1].composite.out -.composite.geometry=0/87%:101%x13% -.filter[0]=watermark -.filter[0].resource=colour:0x6c0101ff -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text=Ticker - provided for reference -.filter[1].producer.family=Sans -.filter[1].producer.size=24 -.filter[1].producer.weight=700 -.filter[1].composite.titles=1 -.filter[1].composite.halign=centre -.filter[1].composite.valign=centre - -super=region -.description=Transcription -.properties.0=filter[1].producer.text -.properties.1=filter[2].producer.text -.properties.align=filter[1].composite.valign -.properties.weight=filter[1].producer.weight -.properties.f0=filter[1].producer.family -.properties.s0=filter[1].producer.size -.properties.f1=filter[2].producer.family -.properties.s1=filter[2].producer.size -.properties.length[0]=composite.out -.period=2 -.composite.geometry=0/71%:100%x16%:0;30=/:x:100 -.composite.luma=%luma01.pgm -.composite.luma_invert=1 -.composite.softness=.3 -.filter[0]=watermark -.filter[0].resource=colour:0xbbbbbbff -.filter[0].composite.geometry=0/0:100%:100%:70 -.filter[0].composite.distort=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text= -.filter[1].producer.family=Sans -.filter[1].producer.size=32 -.filter[1].producer.weight=700 -.filter[1].producer.fgcolour=0x6c0101ff -.filter[1].composite.titles=1 -.filter[1].composite.halign=centre -.filter[1].composite.valign=top -.filter[2]=watermark -.filter[2].resource=pango: -.filter[2].producer.text= -.filter[2].producer.family=Sans -.filter[2].producer.size=32 -.filter[2].producer.fgcolour=0x6c0101ff -.filter[2].composite.titles=1 -.filter[2].composite.halign=centre -.filter[2].composite.valign=bottom - diff --git a/src/modules/feeds/NTSC/obscure.properties b/src/modules/feeds/NTSC/obscure.properties deleted file mode 100644 index f42383192..000000000 --- a/src/modules/feeds/NTSC/obscure.properties +++ /dev/null @@ -1,26 +0,0 @@ -# This properties file describes the fx available to the data_feed and -# data_show filters -# -# Syntax is as follows: -# -# name= -# name.description= -# name.properties.= -# name.=value -# etc -# -# Typically, the is a 'region' and additional filters are -# included as properties using the normal region filter syntax. -# - -obscure=region -.description=Obscure -.properties.geometry=composite.geometry -.properties.resource=resource -.properties.length[0]=composite.out -.composite.geometry= -.resource=rectangle -.composite.refresh=1 -.filter[0]=obscure -.filter[0].start=0/0:100%x100% - diff --git a/src/modules/feeds/PAL/border.properties b/src/modules/feeds/PAL/border.properties deleted file mode 100644 index 5acf2898b..000000000 --- a/src/modules/feeds/PAL/border.properties +++ /dev/null @@ -1,22 +0,0 @@ -border_left=watermark -.description=Border Left -.resource=colour:black -.reverse=1 -.period=2 -.properties.length[0]=composite.out -.composite.geometry=0/0:100%x100%;25=2.5%/17.5%:45%x45% -.composite.halign=c -.composite.valign=c -.composite.fill=1 - -border_right=watermark -.description=Border Right -.resource=colour:black -.reverse=1 -.period=2 -.properties.length[0]=composite.out -.composite.geometry=0/0:100%x100%;25=52.5%/17.5%:45%x45% -.composite.halign=c -.composite.valign=c -.composite.fill=1 - diff --git a/src/modules/feeds/PAL/data_fx.properties b/src/modules/feeds/PAL/data_fx.properties deleted file mode 100644 index 94a5cf202..000000000 --- a/src/modules/feeds/PAL/data_fx.properties +++ /dev/null @@ -1,80 +0,0 @@ -# This properties file describes the fx available to the data_send and -# data_show filters -# -# Syntax is as follows: -# -# name= -# name.description= -# name.properties.= -# name.=value -# etc -# -# Typically, the is a 'region' and additional filters are -# included as properties using the normal region filter syntax. -# - -# -# The titles filter definition -# - -titles=region -.description=Titles -.properties.markup=filter[1].producer.markup -.type.markup=text -.period=2 -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.composite.geometry=5%/70%:90%x20% -.filter[0]=watermark -.filter[0].resource=colour:0x000000ff -.filter[0].composite.geometry=0%/0%:100%x100%:0;5=0%/0%:100%x100%:40 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=Shotcut -.filter[1].composite.geometry=0%/0%:100%x100%:0;8=0%/0%:100%x100%:100 -.filter[1].composite.titles=1 - -# -# The top titles filter definition -# - -top-titles=region -.description=Top Titles -.properties.markup=filter[1].producer.markup -.type.markup=text -.period=2 -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.composite.geometry=5%/5%:90%x20% -.filter[0]=watermark -.filter[0].resource=colour:0x000000ff -.filter[0].composite.geometry=0%/0%:100%x100%:0;5=0%/0%:100%x100%:40 -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=Shotcut -.filter[1].composite.geometry=0%/0%:100%x100%:0;8=0%/0%:100%x100%:100 -.filter[1].composite.titles=1 - -# -# OK - Silly example... -# - -tickertape=region -.description=Tickertape -.properties.markup=filter[1].producer.markup -.type.markup=text -.properties.length[0]=filter[1].composite.out -.composite.geometry=0%/93%:100%x7% -.filter[0]=watermark -.filter[0].resource=colour:0x000000ff -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.markup=Shotcut -.filter[1].composite.geometry=100%/0%:300%x100%:100;-1=-300%/0%:300%x100%:100 -.filter[1].producer.family=San -.filter[1].producer.size=32 -.filter[1].composite.titles=1 - diff --git a/src/modules/feeds/PAL/etv.properties b/src/modules/feeds/PAL/etv.properties deleted file mode 100644 index e45f2823e..000000000 --- a/src/modules/feeds/PAL/etv.properties +++ /dev/null @@ -1,186 +0,0 @@ -# This properties file describes the fx available to the data_feed and -# data_show filters -# -# Syntax is as follows: -# -# name= -# name.description= -# name.properties.= -# name.=value -# etc -# -# Typically, the is a 'region' and additional filters are -# included as properties using the normal region filter syntax. -# - -location=region -.description=Titles -.properties.markup=filter[1].producer.text -.properties.family=filter[1].producer.family -.properties.size=filter[1].producer.size -.period=2 -.properties.length[0]=composite.out -.composite.geometry=0/14%:32%x5%:0;12=/:x:100 -.composite.luma=%luma01.pgm -.composite.softness=.3 -.filter[0]=watermark -.filter[0].resource=colour:0x6c0101ff -.filter[0].composite.distort=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text= -.filter[1].producer.family=Sans -.filter[1].producer.size=24 -.filter[1].composite.geometry=0/0:95%x100% -.filter[1].composite.titles=1 -.filter[1].composite.halign=right -.filter[1].composite.valign=center - -courtesy=region -.description=Courtesy -.properties.markup=filter[1].producer.text -.properties.family=filter[1].producer.family -.properties.size=filter[1].producer.size -.period=2 -.properties.length[0]=composite.out -.composite.geometry=0/20%:32%x5%:0;12=/:x:100 -.composite.luma=%luma01.pgm -.composite.softness=.3 -.filter[0]=watermark -.filter[0].resource=colour:0x6c0101ff -.filter[0].composite.distort=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text= -.filter[1].producer.family=Sans -.filter[1].producer.size=24 -.filter[1].composite.geometry=0/0:95%x100% -.filter[1].composite.titles=1 -.filter[1].composite.halign=right -.filter[1].composite.valign=centre - -exclusive=region -.description=Exclusive -.properties.markup=filter[1].producer.text -.properties.family=filter[1].producer.family -.properties.size=filter[1].producer.size -.period=2 -.properties.length[0]=composite.out -.composite.geometry=-32%/20%:32%x5%;12=0 -.filter[0]=watermark -.filter[0].resource=colour:0x6c0101ff -.filter[0].composite.distort=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text=ETV Exclusive -.filter[1].producer.family=Sans -.filter[1].producer.size=24 -.filter[1].producer.weight=700 -.filter[1].composite.geometry=0/0:95%x100% -.filter[1].composite.titles=1 -.filter[1].composite.halign=right -.filter[1].composite.valign=centre - -file_shot=region -.description=Titles -.period=2 -.properties.family=filter[1].producer.family -.properties.size=filter[1].producer.size -.properties.length[0]=composite.out -.composite.geometry=82%/28%:11%x4%:0;12=/:x:100 -.filter[0]=watermark -.filter[0].resource=colour:0x6c0101ff -.filter[0].composite.distort=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text=File Shot -.filter[1].producer.family=Sans -.filter[1].producer.size=18 -.filter[1].producer.weight=700 -.filter[1].composite.titles=1 -.filter[1].composite.halign=centre -.filter[1].composite.valign=centre - -special=region -.description=Special -.period=2 -.properties.family=filter[1].producer.family -.properties.size=filter[1].producer.size -.properties.length[0]=filter[0].composite.out -.properties.length[1]=filter[1].composite.out -.composite.geometry=65%/65%:35%x6% -.filter[0]=watermark -.filter[0].resource=colour:0x6c0101ff -.filter[0].composite.geometry=100%/0%:100%x100%:0;12=0%/0%:x:100 -.filter[0].composite.distort=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text=Special -.filter[1].producer.family=Sans -.filter[1].producer.size=24 -.filter[1].producer.weight=700 -.filter[1].composite.geometry=100%/0%:100%x100%:0;12=0%/0%:x:100 -.filter[1].composite.titles=1 -.filter[1].composite.halign=centre -.filter[1].composite.valign=centre - -ticker=region -.description=Tickertape -.properties.markup=filter[1].producer.text -.properties.family=filter[1].producer.family -.properties.size=filter[1].producer.size -.properties.length[0]=filter[1].composite.out -.composite.geometry=0/87%:101%x13% -.filter[0]=watermark -.filter[0].resource=colour:0x6c0101ff -.filter[0].composite.titles=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text=Ticker - provided for reference -.filter[1].producer.family=Sans -.filter[1].producer.size=24 -.filter[1].producer.weight=700 -.filter[1].composite.titles=1 -.filter[1].composite.halign=centre -.filter[1].composite.valign=centre - -super=region -.description=Transcription -.properties.0=filter[1].producer.text -.properties.1=filter[2].producer.text -.properties.align=filter[1].composite.valign -.properties.weight=filter[1].producer.weight -.properties.f0=filter[1].producer.family -.properties.s0=filter[1].producer.size -.properties.f1=filter[2].producer.family -.properties.s1=filter[2].producer.size -.properties.length[0]=composite.out -.period=2 -.composite.geometry=0/71%:100%x16%:0;25=/:x:100 -.composite.luma=%luma01.pgm -.composite.luma_invert=1 -.composite.softness=.3 -.filter[0]=watermark -.filter[0].resource=colour:0xbbbbbbff -.filter[0].composite.geometry=0/0:100%:100%:70 -.filter[0].composite.distort=1 -.filter[1]=watermark -.filter[1].resource=pango: -.filter[1].producer.text= -.filter[1].producer.family=Sans -.filter[1].producer.size=32 -.filter[1].producer.weight=700 -.filter[1].producer.fgcolour=0x6c0101ff -.filter[1].composite.titles=1 -.filter[1].composite.halign=centre -.filter[1].composite.valign=top -.filter[2]=watermark -.filter[2].resource=pango: -.filter[2].producer.text= -.filter[2].producer.family=Sans -.filter[2].producer.size=32 -.filter[2].producer.fgcolour=0x6c0101ff -.filter[2].composite.titles=1 -.filter[2].composite.halign=centre -.filter[2].composite.valign=bottom - diff --git a/src/modules/feeds/PAL/example.properties b/src/modules/feeds/PAL/example.properties deleted file mode 100644 index 0509fff87..000000000 --- a/src/modules/feeds/PAL/example.properties +++ /dev/null @@ -1,12 +0,0 @@ -greyscale=greyscale -.description=Greyscale - -sepia=sepia -.description=Sepia - -charcoal=charcoal -.description=Charcoal - -invert=invert -.description=Invert - diff --git a/src/modules/feeds/PAL/obscure.properties b/src/modules/feeds/PAL/obscure.properties deleted file mode 100644 index 3917d9a53..000000000 --- a/src/modules/feeds/PAL/obscure.properties +++ /dev/null @@ -1,35 +0,0 @@ -# This properties file describes the fx available to the data_feed and -# data_show filters -# -# Syntax is as follows: -# -# name= -# name.description= -# name.properties.= -# name.=value -# etc -# -# Typically, the is a 'region' and additional filters are -# included as properties using the normal region filter syntax. -# - -obscure0=region -.description=Primary Obscure -.properties.geometry=composite.geometry -.properties.resource=resource -.properties.length[0]=composite.out -.composite.geometry= -.resource=rectangle -.composite.refresh=1 -.filter[0]=obscure - -obscure1=region -.description=Secondary Obscure -.properties.geometry=composite.geometry -.properties.resource=resource -.properties.length[0]=composite.out -.composite.geometry= -.resource=rectangle -.composite.refresh=1 -.filter[0]=obscure - diff --git a/src/modules/frei0r/CMakeLists.txt b/src/modules/frei0r/CMakeLists.txt index 97919d7d7..4e86cbd47 100644 --- a/src/modules/frei0r/CMakeLists.txt +++ b/src/modules/frei0r/CMakeLists.txt @@ -7,17 +7,22 @@ add_library(mltfrei0r MODULE transition_frei0r.c ) -target_link_libraries(mltfrei0r mlt m ${CMAKE_DL_LIBS}) +target_compile_options(mltfrei0r PRIVATE ${MLT_COMPILE_OPTIONS}) +target_include_directories(mltfrei0r PRIVATE ${FREI0R_INCLUDE_DIRS}) +if(APPLE AND RELOCATABLE) + target_compile_definitions(mltfrei0r PRIVATE RELOCATABLE) +endif() -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltfrei0r PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +target_link_libraries(mltfrei0r PRIVATE mlt m ${CMAKE_DL_LIBS}) -install(TARGETS mltfrei0r LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +set_target_properties(mltfrei0r PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") + +install(TARGETS mltfrei0r LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES filter_cairoblend_mode.yml resolution_scale.yml param_name_map.yaml blacklist.txt not_thread_safe.txt - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/frei0r + DESTINATION ${MLT_INSTALL_DATA_DIR}/frei0r ) diff --git a/src/modules/frei0r/factory.c b/src/modules/frei0r/factory.c index dd72b2ba2..da25f4a18 100644 --- a/src/modules/frei0r/factory.c +++ b/src/modules/frei0r/factory.c @@ -100,13 +100,13 @@ static mlt_properties fill_param_info(mlt_service_type type, const char *service struct stat stat_buff; switch (type) { - case producer_type: + case mlt_service_producer_type: strcpy(servicetype, "producer"); break; - case filter_type: + case mlt_service_filter_type: strcpy(servicetype, "filter"); break; - case transition_type: + case mlt_service_transition_type: strcpy(servicetype, "transition"); break; default: @@ -158,13 +158,13 @@ static mlt_properties fill_param_info(mlt_service_type type, const char *service mlt_properties_set(metadata, "description" , info.explanation); mlt_properties_set(metadata, "creator" , info.author); switch (type) { - case producer_type: + case mlt_service_producer_type: mlt_properties_set(metadata, "type", "producer"); break; - case filter_type: + case mlt_service_filter_type: mlt_properties_set(metadata, "type", "filter"); break; - case transition_type: + case mlt_service_transition_type: mlt_properties_set(metadata, "type", "transition"); break; default: @@ -265,7 +265,7 @@ static void* load_lib(mlt_profile profile, mlt_service_type type , void* handle, mlt_properties properties = NULL; char minor[12]; - if (type == producer_type && info.plugin_type == F0R_PLUGIN_TYPE_SOURCE) { + if (type == mlt_service_producer_type && info.plugin_type == F0R_PLUGIN_TYPE_SOURCE) { mlt_producer producer = mlt_producer_new(profile); if (producer) { @@ -281,7 +281,7 @@ static void* load_lib(mlt_profile profile, mlt_service_type type , void* handle, ret = producer; } - } else if (type == filter_type && info.plugin_type == F0R_PLUGIN_TYPE_FILTER) { + } else if (type == mlt_service_filter_type && info.plugin_type == F0R_PLUGIN_TYPE_FILTER) { mlt_filter filter = mlt_filter_new(); if (filter) { @@ -297,7 +297,7 @@ static void* load_lib(mlt_profile profile, mlt_service_type type , void* handle, ret = filter; } - } else if (type == transition_type && info.plugin_type == F0R_PLUGIN_TYPE_MIXER2) { + } else if (type == mlt_service_transition_type && info.plugin_type == F0R_PLUGIN_TYPE_MIXER2) { mlt_transition transition = mlt_transition_new(); if (transition) { @@ -469,8 +469,8 @@ MLT_REPOSITORY dlclose(handle); continue; } - MLT_REGISTER(producer_type, pluginname, create_frei0r_item); - MLT_REGISTER_METADATA(producer_type, pluginname, fill_param_info, name); + MLT_REGISTER(mlt_service_producer_type, pluginname, create_frei0r_item); + MLT_REGISTER_METADATA(mlt_service_producer_type, pluginname, fill_param_info, name); } else if (firstname && info.plugin_type == F0R_PLUGIN_TYPE_FILTER) { if (mlt_properties_get(mlt_repository_filters(repository), pluginname)) @@ -478,8 +478,8 @@ MLT_REPOSITORY dlclose(handle); continue; } - MLT_REGISTER(filter_type, pluginname, create_frei0r_item); - MLT_REGISTER_METADATA(filter_type, pluginname, fill_param_info, name); + MLT_REGISTER(mlt_service_filter_type, pluginname, create_frei0r_item); + MLT_REGISTER_METADATA(mlt_service_filter_type, pluginname, fill_param_info, name); } else if (firstname && info.plugin_type==F0R_PLUGIN_TYPE_MIXER2 ) { if (mlt_properties_get(mlt_repository_transitions(repository), pluginname)) @@ -487,8 +487,8 @@ MLT_REPOSITORY dlclose(handle); continue; } - MLT_REGISTER(transition_type, pluginname, create_frei0r_item); - MLT_REGISTER_METADATA(transition_type, pluginname, fill_param_info, name); + MLT_REGISTER(mlt_service_transition_type, pluginname, create_frei0r_item); + MLT_REGISTER_METADATA(mlt_service_transition_type, pluginname, fill_param_info, name); } } dlclose(handle); @@ -499,6 +499,6 @@ MLT_REPOSITORY mlt_tokeniser_close(tokeniser); mlt_properties_close(blacklist); free(frei0r_path); - MLT_REGISTER(filter_type, "cairoblend_mode", filter_cairoblend_mode_init); - MLT_REGISTER_METADATA(filter_type, "cairoblend_mode", metadata, "filter_cairoblend_mode.yml"); + MLT_REGISTER(mlt_service_filter_type, "cairoblend_mode", filter_cairoblend_mode_init); + MLT_REGISTER_METADATA(mlt_service_filter_type, "cairoblend_mode", metadata, "filter_cairoblend_mode.yml"); } diff --git a/src/modules/frei0r/filter_frei0r.c b/src/modules/frei0r/filter_frei0r.c index 3daad1219..4bc37ea13 100644 --- a/src/modules/frei0r/filter_frei0r.c +++ b/src/modules/frei0r/filter_frei0r.c @@ -27,7 +27,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format { mlt_filter filter = mlt_frame_pop_service( frame ); - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; mlt_log_debug( MLT_FILTER_SERVICE( filter ), "frei0r %dx%d\n", *width, *height ); int error = mlt_frame_get_image( frame, image, format, width, height, 0 ); diff --git a/src/modules/frei0r/frei0r_helper.c b/src/modules/frei0r/frei0r_helper.c index 6cff2911a..fef61bf5a 100644 --- a/src/modules/frei0r/frei0r_helper.c +++ b/src/modules/frei0r/frei0r_helper.c @@ -233,20 +233,20 @@ int process_frei0r_item( mlt_service service, mlt_position position, double time uint32_t *dest = result; if (info.color_model == F0R_COLOR_MODEL_BGRA8888) { - if (type == producer_type) { + if (type == mlt_service_producer_type) { dest = source[0]; } else { rgba_bgra(image[0], (uint8_t*) result, *width, *height); source[0] = result; dest = (uint32_t*) image[0]; - if (type == transition_type && f0r_update2) { + if (type == mlt_service_transition_type && f0r_update2) { extra = mlt_pool_alloc(video_area * sizeof(uint32_t)); rgba_bgra(image[1], (uint8_t*) extra, *width, *height); source[1] = extra; } } } - if (type == producer_type) { + if (type == mlt_service_producer_type) { if (slice_count > 0) { struct update_context ctx = { .frei0r = inst, @@ -261,7 +261,7 @@ int process_frei0r_item( mlt_service service, mlt_position position, double time } else { f0r_update(inst, time, NULL, dest); } - } else if (type == filter_type) { + } else if (type == mlt_service_filter_type) { if (slice_count > 0) { struct update_context ctx = { .frei0r = inst, @@ -276,7 +276,7 @@ int process_frei0r_item( mlt_service service, mlt_position position, double time } else { f0r_update(inst, time, source[0], dest); } - } else if (type == transition_type && f0r_update2) { + } else if (type == mlt_service_transition_type && f0r_update2) { if (slice_count > 0) { struct update_context ctx = { .frei0r = inst, diff --git a/src/modules/frei0r/producer_frei0r.c b/src/modules/frei0r/producer_frei0r.c index 6a9e6a320..5d74a260c 100644 --- a/src/modules/frei0r/producer_frei0r.c +++ b/src/modules/frei0r/producer_frei0r.c @@ -36,7 +36,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form *height = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->height; // Allocate the image - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; int size = mlt_image_format_size( *format, *width, *height, NULL ); // Allocate the image diff --git a/src/modules/frei0r/transition_frei0r.c b/src/modules/frei0r/transition_frei0r.c index df9527e45..dce41057a 100644 --- a/src/modules/frei0r/transition_frei0r.c +++ b/src/modules/frei0r/transition_frei0r.c @@ -46,7 +46,7 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f int error = 0; // Get the B-frame. - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; error = mlt_frame_get_image( b_frame, &images[1], format, width, height, 0 ); if ( error ) return error; diff --git a/src/modules/gdk/CMakeLists.txt b/src/modules/gdk/CMakeLists.txt index 884a2bd51..debff9aaf 100644 --- a/src/modules/gdk/CMakeLists.txt +++ b/src/modules/gdk/CMakeLists.txt @@ -5,6 +5,8 @@ add_library(mltgdk MODULE producer_pixbuf.c ) +target_compile_options(mltgdk PRIVATE ${MLT_COMPILE_OPTIONS}) + target_link_libraries(mltgdk PRIVATE mlt m Threads::Threads PkgConfig::GdkPixbuf) target_compile_definitions(mltgdk PRIVATE USE_PIXBUF) @@ -18,15 +20,20 @@ if(TARGET PkgConfig::pango AND TARGET PkgConfig::fontconfig) target_sources(mltgdk PRIVATE producer_pango.c) target_link_libraries(mltgdk PRIVATE PkgConfig::pango PkgConfig::fontconfig PkgConfig::pangoft2) target_compile_definitions(mltgdk PRIVATE USE_PANGO) - install(FILES producer_pango.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/gdk) + install(FILES producer_pango.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/gdk) +endif() + +if(CPU_MMX) + target_sources(mltgdk PRIVATE have_mmx.S scale_line_22_yuv_mmx.S) + target_compile_definitions(mltgdk PRIVATE USE_MMX) endif() -# Only for MMX but not x86_64: deprecated -# target_sources(mltgdk PRIVATE have_mmx.S scale_line_22_yuv_mmx.S) +if(CPU_X86_64) + target_compile_definitions(mltgdk PRIVATE ARCH_X86_64) +endif() -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltgdk PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +set_target_properties(mltgdk PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(TARGETS mltgdk LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +install(TARGETS mltgdk LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) -install(FILES filter_rescale.yml producer_pixbuf.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/gdk) +install(FILES filter_rescale.yml producer_pixbuf.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/gdk) diff --git a/src/modules/gdk/factory.c b/src/modules/gdk/factory.c index c66f48157..5692be1ea 100644 --- a/src/modules/gdk/factory.c +++ b/src/modules/gdk/factory.c @@ -87,11 +87,11 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( filter_type, "gtkrescale", create_service ); - MLT_REGISTER( producer_type, "pango", create_service ); - MLT_REGISTER( producer_type, "pixbuf", create_service ); + MLT_REGISTER( mlt_service_filter_type, "gtkrescale", create_service ); + MLT_REGISTER( mlt_service_producer_type, "pango", create_service ); + MLT_REGISTER( mlt_service_producer_type, "pixbuf", create_service ); - MLT_REGISTER_METADATA( filter_type, "gtkrescale", metadata, "filter_rescale.yml" ); - MLT_REGISTER_METADATA( producer_type, "pango", metadata, "producer_pango.yml" ); - MLT_REGISTER_METADATA( producer_type, "pixbuf", metadata, "producer_pixbuf.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "gtkrescale", metadata, "filter_rescale.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "pango", metadata, "producer_pango.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "pixbuf", metadata, "producer_pixbuf.yml" ); } diff --git a/src/modules/gdk/filter_rescale.c b/src/modules/gdk/filter_rescale.c index 6a907156d..01b3cf95d 100644 --- a/src/modules/gdk/filter_rescale.c +++ b/src/modules/gdk/filter_rescale.c @@ -70,16 +70,15 @@ static int filter_scale( mlt_frame this, uint8_t **image, mlt_image_format *form *image = output; break; } - case mlt_image_rgb24: - case mlt_image_rgb24a: - case mlt_image_opengl: + case mlt_image_rgb: + case mlt_image_rgba: { if ( strcmp( interps, "none" ) && ( iwidth != owidth || iheight != oheight ) ) { // Create the output image uint8_t *output = mlt_pool_alloc( size ); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data( *image, GDK_COLORSPACE_RGB, - ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ), 8, iwidth, iheight, + ( *format == mlt_image_rgba ), 8, iwidth, iheight, iwidth * bpp, NULL, NULL ); GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf, owidth, oheight, interp ); g_object_unref( pixbuf ); diff --git a/src/modules/gdk/producer_pango.c b/src/modules/gdk/producer_pango.c index ead6e9123..95ec6edb4 100644 --- a/src/modules/gdk/producer_pango.c +++ b/src/modules/gdk/producer_pango.c @@ -1,6 +1,6 @@ /* * producer_pango.c -- a pango-based titler - * Copyright (C) 2003-2020 Meltytech, LLC + * Copyright (C) 2003-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 @@ -19,9 +19,9 @@ #include #include -#include #include #include +#include #include #include #include @@ -180,7 +180,7 @@ mlt_producer producer_pango_init( const char *filename ) // Get the properties interface mlt_properties properties = MLT_PRODUCER_PROPERTIES( &self->parent ); - mlt_events_register( properties, "fontmap-reload", NULL ); + mlt_events_register( properties, "fontmap-reload" ); mlt_events_listen( properties, producer, "fontmap-reload", (mlt_listener) on_fontmap_reload ); // Set the default properties @@ -227,11 +227,14 @@ mlt_producer producer_pango_init( const char *filename ) int i = 0; mlt_position out_point = 0; mlt_properties contents = mlt_properties_load( filename ); - mlt_geometry key_frames = mlt_geometry_init( ); - struct mlt_geometry_item_s item; + + mlt_animation key_frames = mlt_animation_new(); + struct mlt_animation_item_s item; + item.property = NULL; + item.keyframe_type = mlt_keyframe_discrete; mlt_properties_set_string( properties, "resource", filename ); mlt_properties_set_data( properties, "contents", contents, 0, ( mlt_destructor )mlt_properties_close, NULL ); - mlt_properties_set_data( properties, "key_frames", key_frames, 0, ( mlt_destructor )mlt_geometry_close, NULL ); + mlt_properties_set_data( properties, "key_frames", key_frames, 0, ( mlt_destructor )mlt_animation_close, NULL ); // Make sure we have at least one entry if ( mlt_properties_get( contents, "0" ) == NULL ) @@ -244,10 +247,10 @@ mlt_producer producer_pango_init( const char *filename ) while ( value != NULL && strchr( value, '~' ) ) ( *strchr( value, '~' ) ) = '\n'; item.frame = atoi( name ); - mlt_geometry_insert( key_frames, &item ); + mlt_animation_insert( key_frames, &item ); out_point = MAX( out_point, item.frame ); } - mlt_geometry_interpolate( key_frames ); + mlt_animation_interpolate( key_frames ); mlt_properties_set_position( properties, "length", out_point + 1 ); mlt_properties_set_position( properties, "out", out_point ); } @@ -426,12 +429,13 @@ static void refresh_image( producer_pango self, mlt_frame frame, int width, int { // Check for file support mlt_properties contents = mlt_properties_get_data( producer_props, "contents", NULL ); - mlt_geometry key_frames = mlt_properties_get_data( producer_props, "key_frames", NULL ); - struct mlt_geometry_item_s item; + mlt_animation key_frames = mlt_properties_get_data( producer_props, "key_frames", NULL ); if ( contents != NULL ) { char temp[ 20 ]; - mlt_geometry_prev_key( key_frames, &item, mlt_frame_original_position( frame ) ); + struct mlt_animation_item_s item; + item.property = NULL; + mlt_animation_prev_key( key_frames, &item, mlt_frame_original_position( frame ) ); sprintf( temp, "%d", item.frame ); markup = mlt_properties_get( contents, temp ); } @@ -614,12 +618,12 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form cached = mlt_pool_alloc( sizeof( struct pango_cached_image_s )); cached->width = self->width; cached->height = self->height; - cached->format = gdk_pixbuf_get_has_alpha( self->pixbuf ) ? mlt_image_rgb24a : mlt_image_rgb24; + cached->format = gdk_pixbuf_get_has_alpha( self->pixbuf ) ? mlt_image_rgba : mlt_image_rgb; cached->alpha = NULL; cached->image = NULL; src_stride = gdk_pixbuf_get_rowstride( self->pixbuf ); - dst_stride = self->width * ( mlt_image_rgb24a == cached->format ? 4 : 3 ); + dst_stride = self->width * ( mlt_image_rgba == cached->format ? 4 : 3 ); size = mlt_image_format_size( cached->format, cached->width, cached->height, &bpp ); buf = mlt_pool_alloc( size ); @@ -793,18 +797,9 @@ static GdkPixbuf *pango_get_pixbuf( const char *markup, const char *text, const FT_Bitmap bitmap; PangoFontDescription *desc = NULL; - if( font ) - { - // Support for deprecated "font" property. - desc = pango_font_description_from_string( font ); - pango_ft2_font_map_set_resolution( fontmap, 72, 72 ); - } - else - { - desc = pango_font_description_from_string( family ); - pango_font_description_set_size( desc, PANGO_SCALE * size ); - pango_font_description_set_style( desc, (PangoStyle) style ); - } + desc = pango_font_description_from_string( family ); + pango_font_description_set_size( desc, PANGO_SCALE * size ); + pango_font_description_set_style( desc, (PangoStyle) style ); pango_font_description_set_weight( desc, ( PangoWeight ) weight ); diff --git a/src/modules/gdk/producer_pango.yml b/src/modules/gdk/producer_pango.yml index 5ea0dc945..81f030514 100644 --- a/src/modules/gdk/producer_pango.yml +++ b/src/modules/gdk/producer_pango.yml @@ -33,7 +33,7 @@ notes: > { mlt_profile profile = mlt_profile_init("dv_pal"); mlt_producer producer = mlt_factory_producer(profile, "pango", NULL); - mlt_events_fire(mlt_producer_properties(producer), "fontmap-reload", NULL, NULL ); + mlt_events_fire(mlt_producer_properties(producer), "fontmap-reload", NULL ); mlt_producer_close(producer); mlt_profile_close(profile); }; @@ -143,17 +143,6 @@ parameters: mutable: yes widget: textbox - - identifier: font - title: Font - type: string - description: > - The default typeface to use when not using markup. - FreeType2 renders at 72 dpi. - This property is deprecated. Use family, size and style instead. - readonly: no - mutable: yes - widget: combo - - identifier: family title: Font family type: string diff --git a/src/modules/gdk/producer_pixbuf.c b/src/modules/gdk/producer_pixbuf.c index d06614f17..3bdd70030 100644 --- a/src/modules/gdk/producer_pixbuf.c +++ b/src/modules/gdk/producer_pixbuf.c @@ -1,6 +1,6 @@ /* * producer_pixbuf.c -- raster image loader based upon gdk-pixbuf - * Copyright (C) 2003-2018 Meltytech, LLC + * Copyright (C) 2003-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 @@ -82,9 +82,10 @@ static void refresh_length( mlt_properties properties, producer_pixbuf self ) } } -static void on_property_changed( mlt_service owner, mlt_producer producer, char *name ) +static void on_property_changed( mlt_service owner, mlt_producer producer, mlt_event_data event_data ) { - if ( !strcmp( name, "ttl" ) ) + const char *name = mlt_event_data_to_string(event_data); + if ( name && !strcmp( name, "ttl" ) ) refresh_length( MLT_PRODUCER_PROPERTIES(producer), producer->child ); } @@ -576,7 +577,7 @@ static void refresh_image( producer_pixbuf self, mlt_frame frame, mlt_image_form self->image, self->pixbuf, current_idx, self->image_idx, self->pixbuf_idx, width ); // If we have a pixbuf and we need an image - if ( self->pixbuf && ( !self->image || ( format != mlt_image_none && format != mlt_image_glsl && format != self->format ) ) ) + if ( self->pixbuf && ( !self->image || ( format != mlt_image_none && format != mlt_image_movit && format != self->format ) ) ) { char *interps = mlt_properties_get( properties, "rescale.interp" ); if ( interps ) interps = strdup( interps ); @@ -605,7 +606,7 @@ static void refresh_image( producer_pixbuf self, mlt_frame frame, mlt_image_form int has_alpha = gdk_pixbuf_get_has_alpha( pixbuf ); int src_stride = gdk_pixbuf_get_rowstride( pixbuf ); int dst_stride = self->width * ( has_alpha ? 4 : 3 ); - self->format = has_alpha ? mlt_image_rgb24a : mlt_image_rgb24; + self->format = has_alpha ? mlt_image_rgba : mlt_image_rgb; int image_size = mlt_image_format_size( self->format, width, height, NULL ); self->image = mlt_pool_alloc( image_size ); self->alpha = NULL; @@ -629,7 +630,7 @@ static void refresh_image( producer_pixbuf self, mlt_frame frame, mlt_image_form pthread_mutex_unlock( &g_mutex ); // Convert image to requested format - if ( format != mlt_image_none && format != mlt_image_glsl && format != self->format && frame->convert_image ) + if ( format != mlt_image_none && format != mlt_image_movit && format != self->format && frame->convert_image ) { // cache copies of the image and alpha buffers uint8_t *buffer = self->image; @@ -645,9 +646,7 @@ static void refresh_image( producer_pixbuf self, mlt_frame frame, mlt_image_form buffer = self->image; image_size = mlt_image_format_size( self->format, self->width, self->height, NULL ); self->image = mlt_pool_alloc( image_size ); - // We use height-1 because mlt_image_format_size() uses height + 1. - // XXX Remove -1 when mlt_image_format_size() is changed. - memcpy( self->image, buffer, mlt_image_format_size( self->format, self->width, self->height - 1, NULL ) ); + memcpy( self->image, buffer, mlt_image_format_size( self->format, self->width, self->height, NULL ) ); } } if ( ( buffer = mlt_frame_get_alpha( frame ) ) ) @@ -718,10 +717,8 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form // Clone the image int image_size = mlt_image_format_size( self->format, self->width, self->height, NULL ); uint8_t *image_copy = mlt_pool_alloc( image_size ); - // We use height-1 because mlt_image_format_size() uses height + 1. - // XXX Remove -1 when mlt_image_format_size() is changed. memcpy( image_copy, self->image, - mlt_image_format_size( self->format, self->width, self->height - 1, NULL ) ); + mlt_image_format_size( self->format, self->width, self->height, NULL ) ); // Now update properties so we free the copy after mlt_frame_set_image( frame, image_copy, image_size, mlt_pool_release ); // We're going to pass the copy on diff --git a/src/modules/gtk2/CMakeLists.txt b/src/modules/gtk2/CMakeLists.txt deleted file mode 100644 index 190e5f62c..000000000 --- a/src/modules/gtk2/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -add_library(mltgtk2 MODULE factory.c) -target_link_libraries(mltgtk2 PRIVATE mlt m Threads::Threads) - -if(TARGET GTK2::gtk AND TARGET PkgConfig::fontconfig AND TARGET PkgConfig::harfbuzz) - target_sources(mltgtk2 PRIVATE consumer_gtk2.c) - target_link_libraries(mltgtk2 PRIVATE - GTK2::gtk - GTK2::gdk_pixbuf - GTK2::pango - PkgConfig::fontconfig - PkgConfig::harfbuzz - ) - target_compile_definitions(mltgtk2 PRIVATE USE_GTK2) - install(FILES consumer_gtk2_preview.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/gtk2) -endif() - -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltgtk2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) - -install(TARGETS mltgtk2 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) diff --git a/src/modules/gtk2/Makefile b/src/modules/gtk2/Makefile deleted file mode 100644 index 3b9dba025..000000000 --- a/src/modules/gtk2/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -include ../../../config.mak -include config.mak - -CFLAGS := -I../.. $(CFLAGS) - -LDFLAGS := -L../../framework -lmlt -lpthread -lm $(LDFLAGS) - -TARGET = ../libmltgtk2$(LIBSUF) - -OBJS = factory.o - -ifdef USE_GTK2 -OBJS += consumer_gtk2.o -CFLAGS += $(shell pkg-config $(PKGCONFIG_PREFIX) --cflags gtk+-2.0) -LDFLAGS += $(shell pkg-config $(PKGCONFIG_PREFIX) --libs gtk+-2.0) -endif - -SRCS := $(OBJS:.o=.c) - -all: $(TARGET) - -$(TARGET): $(OBJS) $(ASM_OBJS) - $(CC) $(SHFLAGS) -o $@ $(OBJS) $(ASM_OBJS) $(LDFLAGS) - -depend: $(SRCS) - $(CC) -MM $(CFLAGS) $^ 1>.depend - -distclean: clean - rm -f .depend - -clean: - rm -f $(OBJS) $(ASM_OBJS) $(TARGET) - -install: all - install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" - install -d "$(DESTDIR)$(mltdatadir)/gtk2" - install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/gtk2" - -ifneq ($(wildcard .depend),) -include .depend -endif diff --git a/src/modules/gtk2/configure b/src/modules/gtk2/configure deleted file mode 100755 index 7637abfc3..000000000 --- a/src/modules/gtk2/configure +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh - -if [ "$help" = "1" ] -then - cat << EOF -GTK+ options: - - --gtk2-prefix=path - Override the gtk+-2.0 prefix for pkg-config - -EOF - -else - pkgconfig_prefix= - for i in "$@" - do - case $i in - --gtk2-prefix=* ) pkgconfig_prefix="${i#--gtk2-prefix=}" ;; - esac - done - [ "$pkgconfig_prefix" != "" ] && pkgconfig_prefix="--define-variable=prefix=\"$pkgconfig_prefix\"" - - pkg-config $pkgconfig_prefix gtk+-2.0 2> /dev/null - disable_gtk2=$? - - if [ "$disable_gtk2" != "0" ] - then - echo "- GTK2 components not found: disabling" - touch ../disable-gtk2 - exit 0 - fi - - echo > config.mak - - if [ "$disable_gtk2" = "0" ] - then - echo "CFLAGS += -DUSE_GTK2" >> config.mak - echo "USE_GTK2=1" >> config.mak - else - echo "- gtk2 not found: gtk2 preview disabled" - fi - - [ "$pkgconfig_prefix" != "" ] && echo "PKGCONFIG_PREFIX=$pkgconfig_prefix" >> config.mak - - exit 0 -fi - diff --git a/src/modules/gtk2/consumer_gtk2.c b/src/modules/gtk2/consumer_gtk2.c deleted file mode 100644 index 2dbe9cbad..000000000 --- a/src/modules/gtk2/consumer_gtk2.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * consumer_gtk2.c -- A consumer for GTK2 apps - * Copyright (C) 2003-2014 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 -#ifdef _WIN32 -#include -#else -#include -#endif -#include - -mlt_consumer consumer_gtk2_preview_init( mlt_profile profile, GtkWidget *widget ) -{ - // Create an sdl preview consumer - mlt_consumer consumer = NULL; - - // This is a nasty little hack which is required by SDL - if ( widget != NULL ) - { -#ifdef _WIN32 - HWND xwin = GDK_WINDOW_HWND( widget->window ); -#else - Window xwin = GDK_WINDOW_XWINDOW( widget->window ); -#endif - char windowhack[ 32 ]; - sprintf( windowhack, "%ld", (long) xwin ); - setenv( "SDL_WINDOWID", windowhack, 1 ); - } - - // Create an sdl preview consumer - consumer = mlt_factory_consumer( profile, "sdl_preview", NULL ); - - // Now assign the lock/unlock callbacks - if ( consumer != NULL ) - { - mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); - mlt_properties_set_int( properties, "app_locked", 1 ); - mlt_properties_set_data( properties, "app_lock", gdk_threads_enter, 0, NULL, NULL ); - mlt_properties_set_data( properties, "app_unlock", gdk_threads_leave, 0, NULL, NULL ); - } - - return consumer; -} diff --git a/src/modules/gtk2/consumer_gtk2_preview.yml b/src/modules/gtk2/consumer_gtk2_preview.yml deleted file mode 100644 index efd78a8e0..000000000 --- a/src/modules/gtk2/consumer_gtk2_preview.yml +++ /dev/null @@ -1,13 +0,0 @@ -schema_version: 0.1 -type: consumer -identifier: gtk_preview -title: GTK+ (*deprecated*) -description: A wrapper for sdl_preview that makes it easy to embed in GTK+ applications. -version: 1 -copyright: Meltytech, LLC -creator: Charles Yates -license: LGPLv2.1 -language: en -tags: - - Audio - - Video diff --git a/src/modules/gtk2/deprecated b/src/modules/gtk2/deprecated deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/modules/gtk2/factory.c b/src/modules/gtk2/factory.c deleted file mode 100644 index 96bb20843..000000000 --- a/src/modules/gtk2/factory.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * factory.c -- the factory method interfaces - * Copyright (C) 2003-2014 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 - -#ifdef USE_GTK2 -extern mlt_consumer consumer_gtk2_preview_init( mlt_profile profile, void *widget ); -#endif - -static void initialise( ) -{ - static int init = 0; - if ( init == 0 ) - { - init = 1; - g_type_init( ); - } -} - -void *create_service( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - initialise( ); - -#ifdef USE_GTK2 - if ( !strcmp( id, "gtk2_preview" ) ) - return consumer_gtk2_preview_init( profile, arg ); -#endif - - return NULL; -} - -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 ); - return mlt_properties_parse_yaml( file ); -} - -MLT_REPOSITORY -{ - MLT_REGISTER( consumer_type, "gtk2_preview", create_service ); - - MLT_REGISTER_METADATA( consumer_type, "gtk2_preview", metadata, "consumer_gtk2_preview.yml" ); -} diff --git a/src/modules/jackrack/CMakeLists.txt b/src/modules/jackrack/CMakeLists.txt index f119a9b26..fbf2eae62 100644 --- a/src/modules/jackrack/CMakeLists.txt +++ b/src/modules/jackrack/CMakeLists.txt @@ -1,8 +1,18 @@ -add_library(mltjack MODULE consumer_jack.c factory.c) -target_link_libraries(mltjack PRIVATE mlt Threads::Threads PkgConfig::jack) +add_library(mltjackrack MODULE factory.c) + +target_compile_options(mltjackrack PRIVATE ${MLT_COMPILE_OPTIONS}) + +target_link_libraries(mltjackrack PRIVATE mlt Threads::Threads) + +if(TARGET JACK::JACK) + target_sources(mltjackrack PRIVATE consumer_jack.c) + target_link_libraries(mltjackrack PRIVATE JACK::JACK) + target_compile_definitions(mltjackrack PRIVATE WITH_JACK) + install(FILES consumer_jack.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/jackrack) +endif() if(GPL AND TARGET PkgConfig::xml AND TARGET PkgConfig::glib AND ladspa_h_FOUND) - target_sources(mltjack PRIVATE + target_sources(mltjackrack PRIVATE jack_rack.c lock_free_fifo.c plugin.c @@ -11,23 +21,22 @@ if(GPL AND TARGET PkgConfig::xml AND TARGET PkgConfig::glib AND ladspa_h_FOUND) plugin_settings.c process.c producer_ladspa.c - filter_jackrack.c filter_ladspa.c ) - target_link_libraries(mltjack PRIVATE ${CMAKE_DL_LIBS} m PkgConfig::xml PkgConfig::glib) - target_compile_definitions(mltjack PRIVATE GPL) - install(FILES - filter_jackrack.yml - filter_jack.yml - filter_ladspa.yml - producer_ladspa.yml - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/jackrack - ) -endif() + target_link_libraries(mltjackrack PRIVATE ${CMAKE_DL_LIBS} m PkgConfig::xml PkgConfig::glib) + target_compile_definitions(mltjackrack PRIVATE GPL) + if(APPLE AND RELOCATABLE) + target_compile_definitions(mltjackrack PRIVATE RELOCATABLE) + endif() -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltjack PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) + install(FILES filter_jack.yml filter_ladspa.yml producer_ladspa.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/jackrack) + + if(TARGET JACK::JACK) + target_sources(mltjackrack PRIVATE filter_jackrack.c) + install(FILES filter_jackrack.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/jackrack) + endif() +endif() -install(TARGETS mltjack LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +set_target_properties(mltjackrack PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(FILES consumer_jack.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/jackrack) +install(TARGETS mltjackrack LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) diff --git a/src/modules/jackrack/Makefile b/src/modules/jackrack/Makefile index c29739e6a..dc020e971 100644 --- a/src/modules/jackrack/Makefile +++ b/src/modules/jackrack/Makefile @@ -15,18 +15,20 @@ GPL_OBJS = jack_rack.o \ plugin_settings.o \ process.o \ producer_ladspa.o \ - filter_jackrack.o \ filter_ladspa.o -OBJS = factory.o \ - consumer_jack.o +OBJS = factory.o -CFLAGS += $(shell pkg-config --cflags jack) +ifdef WITH_JACK +GPL_OBJS += filter_jackrack.o +OBJS += consumer_jack.o +CFLAGS += -DWITH_JACK $(shell pkg-config --cflags jack) LDFLAGS += $(shell pkg-config --libs jack) +endif ifdef GPL OBJS += $(GPL_OBJS) -CFLAGS += -DGPL +CFLAGS += -DGPL $(LADSPA_PREFIX) CFLAGS += $(shell pkg-config --cflags libxml-2.0) CFLAGS += $(shell pkg-config $(PKGCONFIG_PREFIX) --cflags glib-2.0) diff --git a/src/modules/jackrack/configure b/src/modules/jackrack/configure index 9d18d0b90..21998cc2c 100755 --- a/src/modules/jackrack/configure +++ b/src/modules/jackrack/configure @@ -6,38 +6,52 @@ then JACK Rack options: --gdk-prefix=path - Override the gdk prefix for pkg-config + --ladspa-prefix=path - Overrride the LADSPA path prefix + --without-jack - Build only the LADSPA producer and filter EOF else - pkg-config jack - disable_jack=$? - echo > config.mak + export without_jack=false + + for i in "$@" + do + case $i in + --gdk-prefix=* ) pkgconfig_prefix="${i#--gdk-prefix=}" ;; + --ladspa-prefix=*) ladspa_prefix="${i#--ladspa-prefix=}" ;; + --without-jack ) without_jack=true ;; + esac + done + + if [ "$without_jack" = "false" ]; then + pkg-config jack + disable_jack=$? + [ "$disable_jack" != "1" ] && "WITH_JACK=1" >> config.mak + fi + if [ "$gpl" = "true" ] then pkg-config libxml-2.0 > /dev/null 2>&1 disable_xml2=$? - ladspa_prefix=`which listplugins 2> /dev/null` - if [ "$ladspa_prefix" != "" ] - then - ladspa_prefix=`dirname "$ladspa_prefix"` - ladspa_prefix=`dirname "$ladspa_prefix"` + if [ "$ladspa_prefix" = "" ]; then + ladspa_prefix=`which listplugins 2> /dev/null` + if [ "$ladspa_prefix" != "" ]; then + ladspa_prefix=`dirname "$ladspa_prefix"` + ladspa_prefix=`dirname "$ladspa_prefix"` + fi else + echo "LADSPA_PREFIX=\"-I$ladspa_prefix/include\"" >> config.mak + fi + if [ "$ladspa_prefix" = "" ]; then ladspa_prefix=`pkg-config --variable=prefix jack` fi disable_ladspa=`[ -f "$ladspa_prefix/include/ladspa.h" ] && echo 0 || echo 1` - echo GPL=1 > config.mak - - for i in "$@" - do - case $i in - --gdk-prefix=* ) pkgconfig_prefix="${i#--gdk-prefix=}" ;; - esac - done + echo GPL=1 >> config.mak + [ "$pkgconfig_prefix" != "" ] && echo "PKGCONFIG_PREFIX=--define-variable=prefix=\"$pkgconfig_prefix\"" >> config.mak fi diff --git a/src/modules/jackrack/consumer_jack.c b/src/modules/jackrack/consumer_jack.c index ac65db749..ba12a182e 100644 --- a/src/modules/jackrack/consumer_jack.c +++ b/src/modules/jackrack/consumer_jack.c @@ -1,6 +1,6 @@ /* * consumer_jack.c -- a JACK audio consumer - * Copyright (C) 2011-2020 Meltytech, LLC + * 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 @@ -64,7 +64,7 @@ static int consumer_stop( mlt_consumer parent ); static int consumer_is_stopped( mlt_consumer parent ); static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); -static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, char *name ); +static void consumer_refresh_cb(mlt_consumer sdl, mlt_consumer parent, mlt_event_data ); static int jack_process( jack_nframes_t frames, void * data ); /** Constructor @@ -140,8 +140,9 @@ mlt_consumer consumer_jack_init( mlt_profile profile, mlt_service_type type, con return NULL; } -static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, char *name ) +static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, mlt_event_data event_data ) { + const char *name = mlt_event_data_to_string(event_data); if ( !strcmp( name, "refresh" ) ) { consumer_jack self = parent->child; @@ -362,8 +363,9 @@ static int consumer_play_video( consumer_jack self, mlt_frame frame ) { // Get the properties of this consumer mlt_properties properties = MLT_CONSUMER_PROPERTIES( &self->parent ); - if ( self->running && !mlt_consumer_is_stopped( &self->parent ) ) - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + if ( self->running && !mlt_consumer_is_stopped( &self->parent ) ) { + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); + } return 0; } diff --git a/src/modules/jackrack/factory.c b/src/modules/jackrack/factory.c index 6ec3a47f0..e5a2824c9 100644 --- a/src/modules/jackrack/factory.c +++ b/src/modules/jackrack/factory.c @@ -1,6 +1,6 @@ /* * factory.c -- the factory method interfaces - * Copyright (C) 2003-2019 Meltytech, LLC + * Copyright (C) 2003-2021 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 @@ -32,7 +32,9 @@ extern mlt_consumer consumer_jack_init( mlt_profile profile, mlt_service_type ty #include #include "plugin_mgr.h" +#ifdef WITH_JACK extern mlt_filter filter_jackrack_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +#endif extern mlt_filter filter_ladspa_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_ladspa_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); @@ -88,7 +90,7 @@ static void add_port_to_metadata( mlt_properties p, plugin_desc_t* desc, int j ) static mlt_properties metadata( mlt_service_type type, const char *id, char *data ) { char file[ PATH_MAX ]; - if( type == filter_type ) + if( type == mlt_service_filter_type ) { snprintf( file, PATH_MAX, "%s/jackrack/%s", mlt_environment( "MLT_DATA" ), strncmp( id, "ladspa.", 7 ) ? data : "filter_ladspa.yml" ); @@ -158,7 +160,7 @@ static mlt_properties metadata( mlt_service_type type, const char *id, char *dat mlt_properties_set( p, "type", "integer" ); mlt_properties_set( p, "readonly", "yes" ); - if( type == filter_type ) + if( type == mlt_service_filter_type ) { p = mlt_properties_new(); snprintf( key, sizeof(key), "%d", mlt_properties_count( params ) ); @@ -193,25 +195,29 @@ MLT_REPOSITORY if( desc->has_input ) { - MLT_REGISTER( filter_type, s, filter_ladspa_init ); - MLT_REGISTER_METADATA( filter_type, s, metadata, NULL ); + MLT_REGISTER( mlt_service_filter_type, s, filter_ladspa_init ); + MLT_REGISTER_METADATA( mlt_service_filter_type, s, metadata, NULL ); } else { - MLT_REGISTER( producer_type, s, producer_ladspa_init ); - MLT_REGISTER_METADATA( producer_type, s, metadata, NULL ); + MLT_REGISTER( mlt_service_producer_type, s, producer_ladspa_init ); + MLT_REGISTER_METADATA( mlt_service_producer_type, s, metadata, NULL ); } free( s ); } mlt_factory_register_for_clean_up( g_jackrack_plugin_mgr, (mlt_destructor) plugin_mgr_destroy ); - MLT_REGISTER( filter_type, "jack", filter_jackrack_init ); - MLT_REGISTER( filter_type, "jackrack", filter_jackrack_init ); - MLT_REGISTER_METADATA( filter_type, "jackrack", metadata, "filter_jackrack.yml" ); - MLT_REGISTER( filter_type, "ladspa", filter_ladspa_init ); - MLT_REGISTER_METADATA( filter_type, "ladspa", metadata, "filter_ladspa.yml" ); +# ifdef WITH_JACK + MLT_REGISTER( mlt_service_filter_type, "jack", filter_jackrack_init ); + MLT_REGISTER( mlt_service_filter_type, "jackrack", filter_jackrack_init ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "jackrack", metadata, "filter_jackrack.yml" ); +# endif + MLT_REGISTER( mlt_service_filter_type, "ladspa", filter_ladspa_init ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "ladspa", metadata, "filter_ladspa.yml" ); +#endif +#ifdef WITH_JACK + MLT_REGISTER( mlt_service_consumer_type, "jack", consumer_jack_init ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "jack", metadata, "consumer_jack.yml" ); #endif - MLT_REGISTER( consumer_type, "jack", consumer_jack_init ); - MLT_REGISTER_METADATA( consumer_type, "jack", metadata, "consumer_jack.yml" ); } diff --git a/src/modules/jackrack/filter_jackrack.c b/src/modules/jackrack/filter_jackrack.c index 91b7b2139..a8eee502c 100644 --- a/src/modules/jackrack/filter_jackrack.c +++ b/src/modules/jackrack/filter_jackrack.c @@ -1,6 +1,6 @@ /* * filter_jackrack.c -- filter audio through Jack and/or LADSPA plugins - * Copyright (C) 2004-2014 Meltytech, LLC + * Copyright (C) 2004-2021 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 @@ -34,22 +34,6 @@ extern pthread_mutex_t g_activate_mutex; #define BUFFER_LEN 204800 * 6 - -static void jack_started_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args ) -{ - listener( owner, service, (mlt_position*) args[0] ); -} - -static void jack_stopped_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args ) -{ - listener( owner, service, (mlt_position*) args[0] ); -} - -static void jack_seek_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args ) -{ - listener( owner, service, (mlt_position*) args[0] ); -} - #define JACKSTATE(x) (x==JackTransportStopped?"stopped":x==JackTransportStarting?"starting":x==JackTransportRolling?"rolling":"unknown") static int jack_sync( jack_transport_state_t state, jack_position_t *jack_pos, void *arg ) @@ -65,7 +49,7 @@ static int jack_sync( jack_transport_state_t state, jack_position_t *jack_pos, v mlt_properties_get_position( properties, "_last_pos" ) ); if ( state == JackTransportStopped ) { - mlt_events_fire( properties, "jack-stopped", &position, NULL ); + mlt_events_fire( properties, "jack-stopped", mlt_event_data_from_int(position) ); mlt_properties_set_int( properties, "_sync_guard", 0 ); } else if ( state == JackTransportStarting ) @@ -74,7 +58,7 @@ static int jack_sync( jack_transport_state_t state, jack_position_t *jack_pos, v if ( !mlt_properties_get_int( properties, "_sync_guard" ) ) { mlt_properties_set_int( properties, "_sync_guard", 1 ); - mlt_events_fire( properties, "jack-started", &position, NULL ); + mlt_events_fire( properties, "jack-started", mlt_event_data_from_int(position) ); } else if ( position >= mlt_properties_get_position( properties, "_last_pos" ) - 2 ) { @@ -104,15 +88,16 @@ static void on_jack_stop( mlt_properties owner, mlt_properties properties ) jack_transport_stop( jack_client ); } -static void on_jack_seek( mlt_properties owner, mlt_filter filter, mlt_position *position ) +static void on_jack_seek( mlt_properties owner, mlt_filter filter, mlt_event_data event_data ) { + mlt_position position = mlt_event_data_to_int(event_data); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); - mlt_log_verbose( MLT_FILTER_SERVICE(filter), "%s: %d\n", __FUNCTION__, *position ); + mlt_log_verbose( MLT_FILTER_SERVICE(filter), "%s: %d\n", __FUNCTION__, position ); mlt_properties_set_int( properties, "_sync_guard", 1 ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); jack_nframes_t jack_frame = jack_get_sample_rate( jack_client ); - jack_frame *= *position / mlt_profile_fps( profile ); + jack_frame *= position / mlt_profile_fps( profile ); jack_transport_locate( jack_client, jack_frame ); } @@ -461,11 +446,11 @@ mlt_filter filter_jackrack_init( mlt_profile profile, mlt_service_type type, con mlt_properties_set_int( properties, "_sync", 1 ); mlt_properties_set_int( properties, "channels", 2 ); - mlt_events_register( properties, "jack-started", (mlt_transmitter) jack_started_transmitter ); - mlt_events_register( properties, "jack-stopped", (mlt_transmitter) jack_stopped_transmitter ); - mlt_events_register( properties, "jack-start", NULL ); - mlt_events_register( properties, "jack-stop", NULL ); - mlt_events_register( properties, "jack-seek", (mlt_transmitter) jack_seek_transmitter ); + mlt_events_register( properties, "jack-started" ); + mlt_events_register( properties, "jack-stopped" ); + mlt_events_register( properties, "jack-start" ); + mlt_events_register( properties, "jack-stop" ); + mlt_events_register( properties, "jack-seek" ); mlt_events_listen( properties, properties, "jack-start", (mlt_listener) on_jack_start ); mlt_events_listen( properties, properties, "jack-stop", (mlt_listener) on_jack_stop ); mlt_events_listen( properties, this, "jack-seek", (mlt_listener) on_jack_seek ); diff --git a/src/modules/jackrack/plugin.c b/src/modules/jackrack/plugin.c index 397b7a55b..ffaea1241 100644 --- a/src/modules/jackrack/plugin.c +++ b/src/modules/jackrack/plugin.c @@ -5,7 +5,7 @@ * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: - * Copyright (C) 2004-2014 Meltytech, LLC + * Copyright (C) 2004-2021 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 @@ -37,8 +37,7 @@ #define CONTROL_FIFO_SIZE 128 - - +#ifdef WITH_JACK /* swap over the jack ports in two plugins */ static void plugin_swap_aux_ports (plugin_t * plugin, plugin_t * other) @@ -53,6 +52,7 @@ plugin_swap_aux_ports (plugin_t * plugin, plugin_t * other) plugin->holders[copy].aux_ports = aux_ports_tmp; } } +#endif /** connect up the ladspa instance's input buffers to the previous plugin's audio memory. make sure to check that plugin->prev @@ -141,6 +141,7 @@ process_remove_plugin (process_info_t * procinfo, plugin_t *plugin) else procinfo->chain_end = plugin->prev; +#ifdef WITH_JACK /* sort out the aux ports */ if (procinfo->jack_client && plugin->desc->aux_channels > 0) { @@ -150,6 +151,7 @@ process_remove_plugin (process_info_t * procinfo, plugin_t *plugin) if (other->desc->id == plugin->desc->id) plugin_swap_aux_ports (plugin, other); } +#endif return plugin; } @@ -230,7 +232,8 @@ process_move_plugin (process_info_t * procinfo, plugin_t *plugin, gint up) else procinfo->chain_end = plugin; } - + +#ifdef WITH_JACK if (procinfo->jack_client && plugin->desc->aux_channels > 0) { plugin_t * other; @@ -240,6 +243,7 @@ process_move_plugin (process_info_t * procinfo, plugin_t *plugin, gint up) if (other->desc->id == plugin->desc->id) plugin_swap_aux_ports (plugin, other); } +#endif } /** exchange an existing plugin for a newly created one */ @@ -260,6 +264,7 @@ process_change_plugin (process_info_t * procinfo, else procinfo->chain_end = new_plugin; +#ifdef WITH_JACK /* sort out the aux ports */ if (procinfo->jack_client && plugin->desc->aux_channels > 0) { @@ -269,6 +274,7 @@ process_change_plugin (process_info_t * procinfo, if (other->desc->id == plugin->desc->id) plugin_swap_aux_ports (plugin, other); } +#endif return plugin; } @@ -364,6 +370,8 @@ plugin_instantiate (const LADSPA_Descriptor * descriptor, return 0; } +#ifdef WITH_JACK + static void plugin_create_aux_ports (plugin_t * plugin, guint copy, jack_rack_t * jack_rack) { @@ -430,6 +438,8 @@ plugin_create_aux_ports (plugin_t * plugin, guint copy, jack_rack_t * jack_rack) g_free (plugin_name); } +#endif + static void plugin_init_holder (plugin_t * plugin, guint copy, @@ -481,8 +491,10 @@ plugin_init_holder (plugin_t * plugin, connect_port (instance, desc->status_port_indicies[i], holder->status_memory + i); } +#ifdef WITH_JACK if (jack_rack->procinfo->jack_client && plugin->desc->aux_channels > 0) plugin_create_aux_ports (plugin, copy, jack_rack); +#endif if (plugin->descriptor->activate) plugin->descriptor->activate (instance); @@ -581,6 +593,7 @@ plugin_destroy (plugin_t * plugin) g_free (plugin->holders[i].status_memory); } +#ifdef WITH_JACK /* aux ports */ if (plugin->jack_rack->procinfo->jack_client && plugin->desc->aux_channels > 0) { @@ -595,6 +608,7 @@ plugin_destroy (plugin_t * plugin) g_free (plugin->holders[i].aux_ports); } +#endif } g_free (plugin->holders); diff --git a/src/modules/jackrack/plugin.h b/src/modules/jackrack/plugin.h index 672608fb9..6e469c4a0 100644 --- a/src/modules/jackrack/plugin.h +++ b/src/modules/jackrack/plugin.h @@ -5,7 +5,7 @@ * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: - * Copyright (C) 2004-2014 Meltytech, LLC + * Copyright (C) 2004-2021 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,7 +28,9 @@ #include #include #include +#ifdef WITH_JACK #include +#endif #include "process.h" #include "plugin_desc.h" @@ -43,7 +45,9 @@ struct _ladspa_holder LADSPA_Data * control_memory; LADSPA_Data * status_memory; +#ifdef WITH_JACK jack_port_t ** aux_ports; +#endif }; struct _plugin diff --git a/src/modules/jackrack/process.c b/src/modules/jackrack/process.c index 574e2e6c5..fc0280deb 100644 --- a/src/modules/jackrack/process.c +++ b/src/modules/jackrack/process.c @@ -5,7 +5,7 @@ * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: - * Copyright (C) 2004-2014 Meltytech, LLC + * Copyright (C) 2004-2021 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 @@ -23,7 +23,9 @@ */ #include +#ifdef WITH_JACK #include +#endif #include #include #include @@ -52,6 +54,8 @@ extern pthread_mutex_t g_activate_mutex; jack_nframes_t sample_rate; jack_nframes_t buffer_size; +#ifdef WITH_JACK + static void jack_shutdown_cb (void * data) { @@ -60,6 +64,8 @@ jack_shutdown_cb (void * data) procinfo->quit = TRUE; } +#endif + /** process messages for plugins' control ports */ void process_control_port_messages (process_info_t * procinfo) { plugin_t * plugin; @@ -88,7 +94,9 @@ void process_control_port_messages (process_info_t * procinfo) { } } -int get_jack_buffers (process_info_t * procinfo, jack_nframes_t frames) { +#ifdef WITH_JACK + +static int get_jack_buffers (process_info_t * procinfo, jack_nframes_t frames) { unsigned long channel; for (channel = 0; channel < procinfo->channels; channel++) @@ -111,6 +119,8 @@ int get_jack_buffers (process_info_t * procinfo, jack_nframes_t frames) { return 0; } +#endif + plugin_t * get_first_enabled_plugin (process_info_t * procinfo) { @@ -164,6 +174,7 @@ connect_chain (process_info_t * procinfo, jack_nframes_t frames) { if (plugin->desc->aux_channels > 0 && plugin->enabled) { +#ifdef WITH_JACK if (procinfo->jack_client) { for (copy = 0; copy < plugin->copies; copy++) @@ -174,6 +185,7 @@ connect_chain (process_info_t * procinfo, jack_nframes_t frames) jack_port_get_buffer (plugin->holders[copy].aux_ports[channel], frames)); } else +#endif { for (copy = 0; copy < frames; copy++) procinfo->silent_buffer[copy] = 0.0; @@ -218,6 +230,7 @@ process_chain (process_info_t * procinfo, jack_nframes_t frames) unsigned long channel; unsigned long i; +#ifdef WITH_JACK if (procinfo->jack_client) { LADSPA_Data zero_signal[frames]; @@ -237,6 +250,7 @@ process_chain (process_info_t * procinfo, jack_nframes_t frames) memcpy (jack_port_get_buffer (plugin->holders[copy].aux_ports[channel], frames), zero_signal, sizeof (LADSPA_Data) * frames); } +#endif first_enabled = get_first_enabled_plugin (procinfo); @@ -337,6 +351,8 @@ int process_ladspa (process_info_t * procinfo, jack_nframes_t frames, return 0; } +#ifdef WITH_JACK + int process_jack (jack_nframes_t frames, void * data) { int err; process_info_t * procinfo; @@ -442,7 +458,7 @@ process_info_connect_port (process_info_t * procinfo, free (jack_ports); } -int +static int process_info_set_port_count (process_info_t * procinfo, unsigned long port_count, gboolean connect_inputs, gboolean connect_outputs) { @@ -509,11 +525,15 @@ process_info_set_port_count (process_info_t * procinfo, return 0; } +#endif + void process_info_set_channels (process_info_t * procinfo, unsigned long channels, gboolean connect_inputs, gboolean connect_outputs) { +#ifdef WITH_JACK process_info_set_port_count (procinfo, channels, connect_inputs, connect_outputs); +#endif procinfo->channels = channels; } @@ -529,10 +549,12 @@ process_info_new (const char * client_name, unsigned long rack_channels, procinfo->chain = NULL; procinfo->chain_end = NULL; +#ifdef WITH_JACK procinfo->jack_client = NULL; procinfo->port_count = 0; procinfo->jack_input_ports = NULL; procinfo->jack_output_ports = NULL; +#endif procinfo->channels = rack_channels; procinfo->quit = FALSE; @@ -562,7 +584,8 @@ process_info_new (const char * client_name, unsigned long rack_channels, else if (isupper (jack_client_name[err])) jack_client_name[err] = tolower (jack_client_name[err]); } - + +#ifdef WITH_JACK err = process_info_connect_jack (procinfo); if (err) { @@ -584,22 +607,25 @@ process_info_new (const char * client_name, unsigned long rack_channels, err = process_info_set_port_count (procinfo, rack_channels, connect_inputs, connect_outputs); if (err) return NULL; +#endif return procinfo; } void process_info_destroy (process_info_t * procinfo) { +#ifdef WITH_JACK if (procinfo->jack_client) { jack_deactivate (procinfo->jack_client); jack_client_close (procinfo->jack_client); } - g_free (procinfo->silent_buffer); g_free (procinfo->jack_input_ports); g_free (procinfo->jack_output_ports); +#endif g_free (procinfo->jack_input_buffers); g_free (procinfo->jack_output_buffers); + g_free (procinfo->silent_buffer); g_free (procinfo); } diff --git a/src/modules/jackrack/process.h b/src/modules/jackrack/process.h index 807acb5e2..1d4cb589d 100644 --- a/src/modules/jackrack/process.h +++ b/src/modules/jackrack/process.h @@ -5,7 +5,7 @@ * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net) * * Modification for MLT: - * Copyright (C) 2004-2014 Meltytech, LLC + * Copyright (C) 2004-2021 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 @@ -26,7 +26,9 @@ #define __JLH_PROCESS_H__ #include +#ifdef WITH_JACK #include +#endif #include #include "lock_free_fifo.h" @@ -41,10 +43,12 @@ struct _process_info { struct _plugin * chain; struct _plugin * chain_end; +#ifdef WITH_JACK jack_client_t * jack_client; unsigned long port_count; jack_port_t ** jack_input_ports; jack_port_t ** jack_output_ports; +#endif unsigned long channels; LADSPA_Data ** jack_input_buffers; @@ -55,6 +59,9 @@ struct _process_info { int quit; }; +#ifndef WITH_JACK +typedef guint32 jack_nframes_t; +#endif extern jack_nframes_t sample_rate; extern jack_nframes_t buffer_size; @@ -68,7 +75,9 @@ void process_info_set_channels (process_info_t * procinfo, int process_ladspa (process_info_t * procinfo, jack_nframes_t frames, LADSPA_Data ** inputs, LADSPA_Data ** outputs); +#ifdef WITH_JACK int process_jack (jack_nframes_t frames, void * data); +#endif void process_quit (process_info_t * procinfo); diff --git a/src/modules/jackrack/producer_ladspa.yml b/src/modules/jackrack/producer_ladspa.yml index 0b367ba13..23912cfba 100644 --- a/src/modules/jackrack/producer_ladspa.yml +++ b/src/modules/jackrack/producer_ladspa.yml @@ -6,7 +6,6 @@ version: 1 copyright: Copyright (C) 2013-2014 Meltytech, LLC license: GPLv2 language: en -creator: Brian Matherly tags: - Audio description: Generate audio using LADSPA plugins. diff --git a/src/modules/kdenlive/CMakeLists.txt b/src/modules/kdenlive/CMakeLists.txt index 527e7b243..0d8e8630d 100644 --- a/src/modules/kdenlive/CMakeLists.txt +++ b/src/modules/kdenlive/CMakeLists.txt @@ -6,17 +6,18 @@ add_library(mltkdenlive MODULE producer_framebuffer.c ) -target_link_libraries(mltkdenlive mlt m) +target_compile_options(mltkdenlive PRIVATE ${MLT_COMPILE_OPTIONS}) -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltkdenlive PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +target_link_libraries(mltkdenlive PRIVATE mlt m) -install(TARGETS mltkdenlive LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +set_target_properties(mltkdenlive PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") + +install(TARGETS mltkdenlive LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES filter_boxblur.yml filter_freeze.yml filter_wave.yml producer_framebuffer.yml - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/kdenlive + DESTINATION ${MLT_INSTALL_DATA_DIR}/kdenlive ) diff --git a/src/modules/kdenlive/factory.c b/src/modules/kdenlive/factory.c index b715f6b8e..b55cd7818 100644 --- a/src/modules/kdenlive/factory.c +++ b/src/modules/kdenlive/factory.c @@ -35,13 +35,13 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( filter_type, "boxblur", filter_boxblur_init ); - MLT_REGISTER( filter_type, "freeze", filter_freeze_init ); - MLT_REGISTER( filter_type, "wave", filter_wave_init ); - MLT_REGISTER( producer_type, "framebuffer", producer_framebuffer_init ); + MLT_REGISTER( mlt_service_filter_type, "boxblur", filter_boxblur_init ); + MLT_REGISTER( mlt_service_filter_type, "freeze", filter_freeze_init ); + MLT_REGISTER( mlt_service_filter_type, "wave", filter_wave_init ); + MLT_REGISTER( mlt_service_producer_type, "framebuffer", producer_framebuffer_init ); - MLT_REGISTER_METADATA( filter_type, "boxblur", metadata, "filter_boxblur.yml" ); - MLT_REGISTER_METADATA( filter_type, "freeze", metadata, "filter_freeze.yml" ); - MLT_REGISTER_METADATA( filter_type, "wave", metadata, "filter_wave.yml" ); - MLT_REGISTER_METADATA( producer_type, "framebuffer", metadata, "producer_framebuffer.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "boxblur", metadata, "filter_boxblur.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "freeze", metadata, "filter_freeze.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "wave", metadata, "filter_wave.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "framebuffer", metadata, "producer_framebuffer.yml" ); } diff --git a/src/modules/kdenlive/filter_boxblur.c b/src/modules/kdenlive/filter_boxblur.c index 6374fe722..94b027a62 100644 --- a/src/modules/kdenlive/filter_boxblur.c +++ b/src/modules/kdenlive/filter_boxblur.c @@ -126,7 +126,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format else { // Get the image - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); // Only process if we have no error and a valid colour space diff --git a/src/modules/kdenlive/producer_framebuffer.c b/src/modules/kdenlive/producer_framebuffer.c index 90ce589a8..103b8fc7f 100644 --- a/src/modules/kdenlive/producer_framebuffer.c +++ b/src/modules/kdenlive/producer_framebuffer.c @@ -1,6 +1,7 @@ /* * producer_framebuffer.c -- create subspeed frames * Copyright (C) 2007 Jean-Baptiste Mardelle + * Copyright (C) 2021 Meltytech, LLC * Author: Jean-Baptiste Mardelle, based on the code of motion_est by Zachary Drew * * This library is free software; you can redistribute it and/or @@ -61,7 +62,7 @@ static int framebuffer_get_image( mlt_frame frame, uint8_t **image, mlt_image_fo if ( !freeze || freeze_after || freeze_before ) { double prod_speed = mlt_properties_get_double( properties, "_speed" ); - double actual_position = prod_speed * ( in + mlt_producer_position( producer ) ); + double actual_position = prod_speed * ( in + mlt_producer_position( producer ) ); if ( mlt_properties_get_int( properties, "reverse" ) ) actual_position = mlt_producer_get_playtime( producer ) - actual_position; @@ -95,9 +96,9 @@ static int framebuffer_get_image( mlt_frame frame, uint8_t **image, mlt_image_fo // Get output buffer int buffersize = 0; - int alphasize = *width * *height; + int alphasize = *width * *height; uint8_t *output = mlt_properties_get_data( properties, "output_buffer", &buffersize ); - uint8_t *output_alpha = mlt_properties_get_data( properties, "output_alpha", NULL ); + uint8_t *output_alpha = mlt_properties_get_data( properties, "output_alpha", NULL ); if( buffersize == 0 || buffersize != size ) { // invalidate cached frame @@ -116,15 +117,15 @@ static int framebuffer_get_image( mlt_frame frame, uint8_t **image, mlt_image_fo if ( output && first_position != -1 ) { // Using the cached frame - uint8_t *image_copy = mlt_pool_alloc( size ); + uint8_t *image_copy = mlt_pool_alloc( size ); memcpy( image_copy, output, size ); - uint8_t *alpha_copy = mlt_pool_alloc( alphasize ); - memcpy( alpha_copy, output_alpha, alphasize ); + uint8_t *alpha_copy = mlt_pool_alloc( alphasize ); + memcpy( alpha_copy, output_alpha, alphasize ); // Set the output image *image = image_copy; mlt_frame_set_image( frame, image_copy, size, mlt_pool_release ); - mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release ); + mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release ); *width = mlt_properties_get_int( properties, "_output_width" ); *height = mlt_properties_get_int( properties, "_output_height" ); @@ -154,7 +155,7 @@ static int framebuffer_get_image( mlt_frame frame, uint8_t **image, mlt_image_fo // Which frames are buffered? uint8_t *first_image = mlt_properties_get_data( first_frame_properties, "image", NULL ); - uint8_t *first_alpha = mlt_properties_get_data( first_frame_properties, "alpha", NULL ); + 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" ) ); @@ -177,21 +178,27 @@ static int framebuffer_get_image( mlt_frame frame, uint8_t **image, mlt_image_fo } if ( !first_alpha ) - { - alphasize = *width * *height; - first_alpha = mlt_frame_get_alpha_mask( first_frame ); - output_alpha = mlt_pool_alloc( alphasize ); - memcpy( output_alpha, first_alpha, alphasize ); - mlt_properties_set_data( properties, "output_alpha", output_alpha, alphasize, mlt_pool_release, NULL ); - } + { + alphasize = *width * *height; + first_alpha = mlt_frame_get_alpha( first_frame ); + if ( !first_alpha ) + { + first_alpha = mlt_pool_alloc( alphasize ); + memset( first_alpha, 255, alphasize ); + mlt_frame_set_alpha( first_frame, first_alpha, alphasize, mlt_pool_release ); + } + output_alpha = mlt_pool_alloc( alphasize ); + memcpy( output_alpha, first_alpha, alphasize ); + mlt_properties_set_data( properties, "output_alpha", output_alpha, alphasize, mlt_pool_release, NULL ); + } mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); // Create a copy uint8_t *image_copy = mlt_pool_alloc( size ); memcpy( image_copy, first_image, size ); - uint8_t *alpha_copy = mlt_pool_alloc( alphasize ); - memcpy( alpha_copy, first_alpha, alphasize ); + uint8_t *alpha_copy = mlt_pool_alloc( alphasize ); + memcpy( alpha_copy, first_alpha, alphasize ); // Set the output image *image = image_copy; @@ -221,32 +228,32 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i if ( first_frame == NULL ) { - // Get the frame to cache from the real producer - mlt_producer real_producer = mlt_properties_get_data( properties, "producer", NULL ); + // Get the frame to cache from the real producer + mlt_producer real_producer = mlt_properties_get_data( properties, "producer", NULL ); - // Get the producer speed - double prod_speed = mlt_properties_get_double( properties, "_speed" ); + // Get the producer speed + double prod_speed = mlt_properties_get_double( properties, "_speed" ); - // Seek the producer to the correct place - mlt_producer_seek( real_producer, mlt_producer_position( producer ) * prod_speed ); + // Seek the producer to the correct place + mlt_producer_seek( real_producer, mlt_producer_position( producer ) * prod_speed ); - // Get the frame - mlt_service_get_frame( MLT_PRODUCER_SERVICE( real_producer ), &first_frame, index ); + // Get the frame + mlt_service_get_frame( MLT_PRODUCER_SERVICE( real_producer ), &first_frame, index ); - // Cache the frame - mlt_properties_set_data( properties, "first_frame", first_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); + // Cache the frame + mlt_properties_set_data( properties, "first_frame", first_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); - // Find the original producer's format - int width = 0; - int height = 0; - mlt_image_format format = mlt_image_none; - uint8_t *image = NULL; - int error = mlt_frame_get_image( first_frame, &image, &format, &width, &height, 0 ); - if ( !error ) - { + // Find the original producer's format + int width = 0; + int height = 0; + mlt_image_format format = mlt_image_none; + uint8_t *image = NULL; + int error = mlt_frame_get_image( first_frame, &image, &format, &width, &height, 0 ); + if ( !error ) + { // cache the original producer's pixel format mlt_properties_set_int( properties, "_original_format", (int) format ); - } + } } mlt_properties_inherit( frame_properties, MLT_FRAME_PROPERTIES(first_frame) ); @@ -254,7 +261,7 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i double force_aspect_ratio = mlt_properties_get_double( properties, "force_aspect_ratio" ); if ( force_aspect_ratio <= 0.0 ) force_aspect_ratio = mlt_properties_get_double( properties, "aspect_ratio" ); mlt_properties_set_double( frame_properties, "aspect_ratio", force_aspect_ratio ); - + // Give the returned frame temporal identity mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); @@ -288,10 +295,10 @@ mlt_producer producer_framebuffer_init( mlt_profile profile, mlt_service_type ty /** * Speed must be appended to the filename with '?'. To play your video at 50%: - melt framebuffer:my_video.mpg?0.5 + melt framebuffer:my_video.mpg?0.5 * Stroboscope effect can be obtained by adding a stobe=x parameter, where - x is the number of frames that will be ignored. + x is the number of frames that will be ignored. * You can play the movie backwards by adding reverse=1 diff --git a/src/modules/kino/Makefile b/src/modules/kino/Makefile deleted file mode 100644 index 8452dd99c..000000000 --- a/src/modules/kino/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -include ../../../config.mak -include config.mak - -CFLAGS := -I../../ $(CFLAGS) -CXXFLAGS := $(CFLAGS) -Wno-deprecated $(CXXFLAGS) - -LDFLAGS := -L../../framework -lmlt -lpthread $(LDFLAGS) - -TARGET = ../libmltkino.so - -OBJS = factory.o producer_kino.o -CPPOBJS = kino_wrapper.o avi.o error.o filehandler.o riff.o - -LDFLAGS += -lstdc++ - -ifdef HAVE_LIBQUICKTIME -CFLAGS += `pkg-config --cflags libquicktime` -CXXFLAGS += `pkg-config --cflags libquicktime` -LDFLAGS += `pkg-config --libs libquicktime` -endif - -ifdef HAVE_LIBDV -CFLAGS += `pkg-config --cflags libdv` -LDFLAGS += `pkg-config --libs libdv` -endif - - -SRCS := $(OBJS:.o=.c) $(CPPOBJS:.o=.cc) - -all: $(TARGET) - -$(TARGET): $(OBJS) $(CPPOBJS) - $(CXX) -shared -o $@ $(OBJS) $(CPPOBJS) $(LDFLAGS) - -depend: $(SRCS) - $(CC) -MM $(CFLAGS) $^ 1>.depend - -distclean: clean - rm -f .depend config.h config.mak - -clean: - rm -f $(OBJS) $(TARGET) $(CPPOBJS) - -install: all - install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" - -ifneq ($(wildcard .depend),) -include .depend -endif diff --git a/src/modules/kino/avi.cc b/src/modules/kino/avi.cc deleted file mode 100644 index 799fb449f..000000000 --- a/src/modules/kino/avi.cc +++ /dev/null @@ -1,1713 +0,0 @@ -/* -* avi.cc library for AVI file format i/o -* Copyright (C) 2000 - 2002 Arne Schirmacher -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -// C++ includes - -#include -#include -#include - -using std::cout; -using std::hex; -using std::dec; -using std::setw; -using std::setfill; -using std::endl; - -// C includes - -#include -#include -#include -#include -#include - -// local includes - -#include "error.h" -#include "riff.h" -#include "avi.h" - -#define PADDING_SIZE (512) -#define PADDING_1GB (0x40000000) -#define IX00_INDEX_SIZE (4028) - -#define AVIF_HASINDEX 0x00000010 -#define AVIF_MUSTUSEINDEX 0x00000020 -#define AVIF_TRUSTCKTYPE 0x00000800 -#define AVIF_ISINTERLEAVED 0x00000100 -#define AVIF_WASCAPTUREFILE 0x00010000 -#define AVIF_COPYRIGHTED 0x00020000 - - -//static char g_zeroes[ PADDING_SIZE ]; - -/** The constructor - - \todo mainHdr not initialized - \todo add checking for NULL pointers - -*/ - -AVIFile::AVIFile() : RIFFFile(), - idx1( NULL ), file_list( -1 ), riff_list( -1 ), - hdrl_list( -1 ), avih_chunk( -1 ), movi_list( -1 ), junk_chunk( -1 ), idx1_chunk( -1 ), - index_type( -1 ), current_ix00( -1 ), odml_list( -1 ), dmlh_chunk( -1 ), isUpdateIdx1( true ) -{ - // cerr << "0x" << hex << (long)this << dec << " AVIFile::AVIFile() : RIFFFile(), ..." << endl; - - for ( int i = 0; i < 2; ++i ) - { - indx[ i ] = new AVISuperIndex; - memset( indx[ i ], 0, sizeof( AVISuperIndex ) ); - ix[ i ] = new AVIStdIndex; - memset( ix[ i ], 0, sizeof( AVIStdIndex ) ); - indx_chunk[ i ] = -1; - ix_chunk[ i ] = -1; - strl_list[ i ] = -1; - strh_chunk[ i ] = -1; - strf_chunk[ i ] = -1; - } - idx1 = new AVISimpleIndex; - memset( idx1, 0, sizeof( AVISimpleIndex ) ); - memset( dmlh, 0, sizeof( dmlh ) ); - memset( &mainHdr, 0, sizeof( mainHdr ) ); - memset( &streamHdr, 0, sizeof( streamHdr ) ); -} - - -/** The copy constructor - - \todo add checking for NULL pointers - -*/ - -AVIFile::AVIFile( const AVIFile& avi ) : RIFFFile( avi ) -{ - // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile::AVIFile(const AVIFile& avi) : RIFFFile(avi)" << endl; - - mainHdr = avi.mainHdr; - idx1 = new AVISimpleIndex; - *idx1 = *avi.idx1; - file_list = avi.file_list; - riff_list = avi.riff_list; - hdrl_list = avi.hdrl_list; - avih_chunk = avi.avih_chunk; - movi_list = avi.movi_list; - junk_chunk = avi.junk_chunk; - idx1_chunk = avi.idx1_chunk; - - for ( int i = 0; i < 2; ++i ) - { - indx[ i ] = new AVISuperIndex; - *indx[ i ] = *avi.indx[ i ]; - ix[ i ] = new AVIStdIndex; - *ix[ i ] = *avi.ix[ i ]; - indx_chunk[ i ] = avi.indx_chunk[ i ]; - ix_chunk[ i ] = avi.ix_chunk[ i ]; - strl_list[ i ] = avi.strl_list[ i ]; - strh_chunk[ i ] = avi.strh_chunk[ i ]; - strf_chunk[ i ] = avi.strf_chunk[ i ]; - } - - index_type = avi.index_type; - current_ix00 = avi.current_ix00; - - for ( int i = 0; i < 62; ++i ) - dmlh[ i ] = avi.dmlh[ i ]; - - isUpdateIdx1 = avi.isUpdateIdx1; - - odml_list = 0; - dmlh_chunk = 0; - memset( &streamHdr, 0, sizeof( streamHdr ) ); -} - - -/** The assignment operator - -*/ - -AVIFile& AVIFile::operator=( const AVIFile& avi ) -{ - // cerr << "0x" << hex << (long)this << dec << " 0x" << hex << (long)&avi << dec << " AVIFile& AVIFile::operator=(const AVIFile& avi)" << endl; - - if ( this != &avi ) - { - RIFFFile::operator=( avi ); - mainHdr = avi.mainHdr; - *idx1 = *avi.idx1; - file_list = avi.file_list; - riff_list = avi.riff_list; - hdrl_list = avi.hdrl_list; - avih_chunk = avi.avih_chunk; - movi_list = avi.movi_list; - junk_chunk = avi.junk_chunk; - idx1_chunk = avi.idx1_chunk; - - for ( int i = 0; i < 2; ++i ) - { - *indx[ i ] = *avi.indx[ i ]; - *ix[ i ] = *avi.ix[ i ]; - indx_chunk[ i ] = avi.indx_chunk[ i ]; - ix_chunk[ i ] = avi.ix_chunk[ i ]; - strl_list[ i ] = avi.strl_list[ i ]; - strh_chunk[ i ] = avi.strh_chunk[ i ]; - strf_chunk[ i ] = avi.strf_chunk[ i ]; - } - - index_type = avi.index_type; - current_ix00 = avi.current_ix00; - - for ( int i = 0; i < 62; ++i ) - dmlh[ i ] = avi.dmlh[ i ]; - - isUpdateIdx1 = avi.isUpdateIdx1; - } - return *this; -} - - -/** The destructor - -*/ - -AVIFile::~AVIFile() -{ - // cerr << "0x" << hex << (long)this << dec << " AVIFile::~AVIFile()" << endl; - - for ( int i = 0; i < 2; ++i ) - { - delete ix[ i ]; - delete indx[ i ]; - } - delete idx1; -} - -/** Initialize the AVI structure to its initial state, either for PAL or NTSC format - - Initialize the AVIFile attributes: mainHdr, indx, ix00, idx1 - - \todo consolidate AVIFile::Init, AVI1File::Init, AVI2File::Init. They are somewhat redundant. - \param format pass AVI_PAL or AVI_NTSC - \param sampleFrequency the sample frequency of the audio content - \param indexType pass AVI_SMALL_INDEX or AVI_LARGE_INDEX - -*/ - -void AVIFile::Init( int format, int sampleFrequency, int indexType ) -{ - int i, j; - - assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) ); - - index_type = indexType; - - switch ( format ) - { - case AVI_PAL: - mainHdr.dwMicroSecPerFrame = 40000; - mainHdr.dwSuggestedBufferSize = 144008; - break; - - case AVI_NTSC: - mainHdr.dwMicroSecPerFrame = 33366; - mainHdr.dwSuggestedBufferSize = 120008; - break; - - default: /* no default allowed */ - assert( 0 ); - break; - } - - /* Initialize the 'avih' chunk */ - - mainHdr.dwMaxBytesPerSec = 3600000 + sampleFrequency * 4; - mainHdr.dwPaddingGranularity = PADDING_SIZE; - mainHdr.dwFlags = AVIF_TRUSTCKTYPE; - if ( indexType & AVI_SMALL_INDEX ) - mainHdr.dwFlags |= AVIF_HASINDEX; - mainHdr.dwTotalFrames = 0; - mainHdr.dwInitialFrames = 0; - mainHdr.dwStreams = 1; - mainHdr.dwWidth = 0; - mainHdr.dwHeight = 0; - mainHdr.dwReserved[ 0 ] = 0; - mainHdr.dwReserved[ 1 ] = 0; - mainHdr.dwReserved[ 2 ] = 0; - mainHdr.dwReserved[ 3 ] = 0; - - /* Initialize the 'idx1' chunk */ - - for ( int i = 0; i < 8000; ++i ) - { - idx1->aIndex[ i ].dwChunkId = 0; - idx1->aIndex[ i ].dwFlags = 0; - idx1->aIndex[ i ].dwOffset = 0; - idx1->aIndex[ i ].dwSize = 0; - } - idx1->nEntriesInUse = 0; - - /* Initialize the 'indx' chunk */ - - for ( i = 0; i < 2; ++i ) - { - indx[ i ] ->wLongsPerEntry = 4; - indx[ i ] ->bIndexSubType = 0; - indx[ i ] ->bIndexType = KINO_AVI_INDEX_OF_INDEXES; - indx[ i ] ->nEntriesInUse = 0; - indx[ i ] ->dwReserved[ 0 ] = 0; - indx[ i ] ->dwReserved[ 1 ] = 0; - indx[ i ] ->dwReserved[ 2 ] = 0; - for ( j = 0; j < 2014; ++j ) - { - indx[ i ] ->aIndex[ j ].qwOffset = 0; - indx[ i ] ->aIndex[ j ].dwSize = 0; - indx[ i ] ->aIndex[ j ].dwDuration = 0; - } - } - - /* The ix00 and ix01 chunk will be added dynamically in avi_write_frame - as needed */ - - /* Initialize the 'dmlh' chunk. I have no clue what this means - though */ - - for ( i = 0; i < 62; ++i ) - dmlh[ i ] = 0; - //dmlh[0] = -1; /* frame count + 1? */ - -} - - -/** Find position and size of a given frame in the file - - Depending on which index is available, search one of them to - find position and frame size - - \todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr. - \todo all index related operations should be isolated - \param offset the file offset to the start of the frame - \param size the size of the frame - \param frameNum the number of the frame we wish to find - \return 0 if the frame could be found, -1 otherwise -*/ - -int AVIFile::GetDVFrameInfo( off_t &offset, int &size, int frameNum ) -{ - switch ( index_type ) - { - case AVI_LARGE_INDEX: - - /* find relevant index in indx0 */ - - int i; - - for ( i = 0; frameNum >= indx[ 0 ] ->aIndex[ i ].dwDuration; frameNum -= indx[ 0 ] ->aIndex[ i ].dwDuration, ++i ) - ; - - if ( i != current_ix00 ) - { - fail_if( lseek( fd, indx[ 0 ] ->aIndex[ i ].qwOffset + RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, ix[ 0 ], indx[ 0 ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) ); - current_ix00 = i; - } - - if ( frameNum < ix[ 0 ] ->nEntriesInUse ) - { - offset = ix[ 0 ] ->qwBaseOffset + ix[ 0 ] ->aIndex[ frameNum ].dwOffset; - size = ix[ 0 ] ->aIndex[ frameNum ].dwSize; - return 0; - } - else - return -1; - break; - - case AVI_SMALL_INDEX: - int index = -1; - int frameNumIndex = 0; - for ( int i = 0; i < idx1->nEntriesInUse; ++i ) - { - FOURCC chunkID1 = make_fourcc( "00dc" ); - FOURCC chunkID2 = make_fourcc( "00db" ); - if ( idx1->aIndex[ i ].dwChunkId == chunkID1 || - idx1->aIndex[ i ].dwChunkId == chunkID2 ) - { - if ( frameNumIndex == frameNum ) - { - index = i; - break; - } - ++frameNumIndex; - } - } - if ( index != -1 ) - { - // compatibility check for broken dvgrab dv2 format - if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset ) - { - offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE; - } - else - { - // new, correct dv2 format - offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE + GetDirectoryEntry( movi_list ).offset; - } - size = idx1->aIndex[ index ].dwSize; - return 0; - } - else - return -1; - break; - } - return -1; -} - -/** Find position and size of a given frame in the file - - Depending on which index is available, search one of them to - find position and frame size - - \todo the size parameter is redundant. All frames have the same size, which is also in the mainHdr. - \todo all index related operations should be isolated - \param offset the file offset to the start of the frame - \param size the size of the frame - \param frameNum the number of the frame we wish to find - \param chunkID the ID of the type of chunk we want - \return 0 if the frame could be found, -1 otherwise -*/ - -int AVIFile::GetFrameInfo( off_t &offset, int &size, int frameNum, FOURCC chunkID ) -{ - if ( index_type & AVI_LARGE_INDEX ) - { - int i; - - for ( i = 0; frameNum >= indx[ 0 ] ->aIndex[ i ].dwDuration; frameNum -= indx[ 0 ] ->aIndex[ i ].dwDuration, ++i ) - ; - - if ( i != current_ix00 ) - { - fail_if( lseek( fd, indx[ 0 ] ->aIndex[ i ].qwOffset + RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, ix[ 0 ], indx[ 0 ] ->aIndex[ i ].dwSize - RIFF_HEADERSIZE ) ); - current_ix00 = i; - } - - if ( frameNum < ix[ 0 ] ->nEntriesInUse ) - { - if ( ( FOURCC ) ix[ 0 ] ->dwChunkId == chunkID ) - { - offset = ix[ 0 ] ->qwBaseOffset + ix[ 0 ] ->aIndex[ frameNum ].dwOffset; - size = ix[ 0 ] ->aIndex[ frameNum ].dwSize; - return 0; - } - } - } - if ( index_type & AVI_SMALL_INDEX ) - { - int index = -1; - int frameNumIndex = 0; - for ( int i = 0; i < idx1->nEntriesInUse; ++i ) - { - if ( idx1->aIndex[ i ].dwChunkId == chunkID ) - { - if ( frameNumIndex == frameNum ) - { - index = i; - break; - } - ++frameNumIndex; - } - } - if ( index != -1 ) - { - // compatibility check for broken dvgrab dv2 format - if ( idx1->aIndex[ 0 ].dwOffset > GetDirectoryEntry( movi_list ).offset ) - { - offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE; - } - else - { - // new, correct dv2 format - offset = idx1->aIndex[ index ].dwOffset + RIFF_HEADERSIZE + GetDirectoryEntry( movi_list ).offset; - } - size = idx1->aIndex[ index ].dwSize; - return 0; - } - } - return -1; -} - -/** Read in a frame - - \todo we actually don't need the frame here, we could use just a void pointer - \param frame a reference to the frame object that will receive the frame data - \param frameNum the frame number to read - \return 0 if the frame could be read, -1 otherwise -*/ - -int AVIFile::GetDVFrame( uint8_t *data, int frameNum ) -{ - off_t offset; - int size; - - if ( GetDVFrameInfo( offset, size, frameNum ) != 0 || size < 0 ) - return -1; - pthread_mutex_lock( &file_mutex ); - fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, data, size ) ); - pthread_mutex_unlock( &file_mutex ); - - return 0; -} - -/** Read in a frame - - \param data a pointer to the audio buffer - \param frameNum the frame number to read - \param chunkID the ID of the type of chunk we want - \return the size the of the frame data, 0 if could not be read -*/ - -int AVIFile::getFrame( void *data, int frameNum, FOURCC chunkID ) -{ - off_t offset; - int size; - - if ( GetFrameInfo( offset, size, frameNum, chunkID ) != 0 ) - return 0; - fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, data, size ) ); - - return size; -} - -int AVIFile::GetTotalFrames() const -{ - return mainHdr.dwTotalFrames; -} - - -/** prints out a directory entry in text form - - Every subclass of RIFFFile is supposed to override this function - and to implement it for the entry types it knows about. For all - other entry types it should call its parent::PrintDirectoryData. - - \todo use 64 bit routines - \param entry the entry to print -*/ - -void AVIFile::PrintDirectoryEntryData( const RIFFDirEntry &entry ) const -{ - static FOURCC lastStreamType = make_fourcc( " " ); - - if ( entry.type == make_fourcc( "avih" ) ) - { - - int i; - MainAVIHeader main_avi_header; - - fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, &main_avi_header, sizeof( MainAVIHeader ) ) ); - - cout << " dwMicroSecPerFrame: " << ( int ) main_avi_header.dwMicroSecPerFrame << endl - << " dwMaxBytesPerSec: " << ( int ) main_avi_header.dwMaxBytesPerSec << endl - << " dwPaddingGranularity: " << ( int ) main_avi_header.dwPaddingGranularity << endl - << " dwFlags: " << ( int ) main_avi_header.dwFlags << endl - << " dwTotalFrames: " << ( int ) main_avi_header.dwTotalFrames << endl - << " dwInitialFrames: " << ( int ) main_avi_header.dwInitialFrames << endl - << " dwStreams: " << ( int ) main_avi_header.dwStreams << endl - << " dwSuggestedBufferSize: " << ( int ) main_avi_header.dwSuggestedBufferSize << endl - << " dwWidth: " << ( int ) main_avi_header.dwWidth << endl - << " dwHeight: " << ( int ) main_avi_header.dwHeight << endl; - for ( i = 0; i < 4; ++i ) - cout << " dwReserved[" << i << "]: " << ( int ) main_avi_header.dwReserved[ i ] << endl; - - } - else if ( entry.type == make_fourcc( "strh" ) ) - { - - AVIStreamHeader avi_stream_header; - - fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, &avi_stream_header, sizeof( AVIStreamHeader ) ) ); - - lastStreamType = avi_stream_header.fccType; - - cout << " fccType: '" - << ((char *)&avi_stream_header.fccType)[0] - << ((char *)&avi_stream_header.fccType)[1] - << ((char *)&avi_stream_header.fccType)[2] - << ((char *)&avi_stream_header.fccType)[3] - << '\'' << endl - << " fccHandler: '" - << ((char *)&avi_stream_header.fccHandler)[0] - << ((char *)&avi_stream_header.fccHandler)[1] - << ((char *)&avi_stream_header.fccHandler)[2] - << ((char *)&avi_stream_header.fccHandler)[3] - << '\'' << endl - << " dwFlags: " << ( int ) avi_stream_header.dwFlags << endl - << " wPriority: " << ( int ) avi_stream_header.wPriority << endl - << " wLanguage: " << ( int ) avi_stream_header.wLanguage << endl - << " dwInitialFrames: " << ( int ) avi_stream_header.dwInitialFrames << endl - << " dwScale: " << ( int ) avi_stream_header.dwScale << endl - << " dwRate: " << ( int ) avi_stream_header.dwRate << endl - << " dwLength: " << ( int ) avi_stream_header.dwLength << endl - << " dwQuality: " << ( int ) avi_stream_header.dwQuality << endl - << " dwSampleSize: " << ( int ) avi_stream_header.dwSampleSize << endl; - - } - else if ( entry.type == make_fourcc( "indx" ) ) - { - - int i; - AVISuperIndex avi_super_index; - - fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, &avi_super_index, sizeof( AVISuperIndex ) ) ); - - cout << " wLongsPerEntry: " << ( int ) avi_super_index.wLongsPerEntry - << endl - << " bIndexSubType: " << ( int ) avi_super_index.bIndexSubType << endl - << " bIndexType: " << ( int ) avi_super_index.bIndexType << endl - << " nEntriesInUse: " << ( int ) avi_super_index.nEntriesInUse << endl - << " dwChunkId: '" - << ((char *)&avi_super_index.dwChunkId)[0] - << ((char *)&avi_super_index.dwChunkId)[1] - << ((char *)&avi_super_index.dwChunkId)[2] - << ((char *)&avi_super_index.dwChunkId)[3] - << '\'' << endl - << " dwReserved[0]: " << ( int ) avi_super_index.dwReserved[ 0 ] << endl - << " dwReserved[1]: " << ( int ) avi_super_index.dwReserved[ 1 ] << endl - << " dwReserved[2]: " << ( int ) avi_super_index.dwReserved[ 2 ] << endl; - for ( i = 0; i < avi_super_index.nEntriesInUse; ++i ) - { - cout << ' ' << setw( 4 ) << setfill( ' ' ) << i - << ": qwOffset : 0x" << setw( 12 ) << setfill( '0' ) << hex << avi_super_index.aIndex[ i ].qwOffset << endl - << " dwSize : 0x" << setw( 8 ) << avi_super_index.aIndex[ i ].dwSize << endl - << " dwDuration : " << dec << avi_super_index.aIndex[ i ].dwDuration << endl; - } - } - else if ( entry.type == make_fourcc( "strf" ) ) - { - if ( lastStreamType == make_fourcc( "auds" ) ) - { - WAVEFORMATEX waveformatex; - fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, &waveformatex, sizeof( WAVEFORMATEX ) ) ); - cout << " waveformatex.wFormatTag : " << waveformatex.wFormatTag << endl; - cout << " waveformatex.nChannels : " << waveformatex.nChannels << endl; - cout << " waveformatex.nSamplesPerSec : " << waveformatex.nSamplesPerSec << endl; - cout << " waveformatex.nAvgBytesPerSec: " << waveformatex.nAvgBytesPerSec << endl; - cout << " waveformatex.nBlockAlign : " << waveformatex.nBlockAlign << endl; - cout << " waveformatex.wBitsPerSample : " << waveformatex.wBitsPerSample << endl; - cout << " waveformatex.cbSize : " << waveformatex.cbSize << endl; - } - else if ( lastStreamType == make_fourcc( "vids" ) ) - { - BITMAPINFOHEADER bitmapinfo; - fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, &bitmapinfo, sizeof( BITMAPINFOHEADER ) ) ); - cout << " bitmapinfo.biSize : " << bitmapinfo.biSize << endl; - cout << " bitmapinfo.biWidth : " << bitmapinfo.biWidth << endl; - cout << " bitmapinfo.biHeight : " << bitmapinfo.biHeight << endl; - cout << " bitmapinfo.biPlanes : " << bitmapinfo.biPlanes << endl; - cout << " bitmapinfo.biBitCount : " << bitmapinfo.biBitCount << endl; - cout << " bitmapinfo.biCompression : " << bitmapinfo.biCompression << endl; - cout << " bitmapinfo.biSizeImage : " << bitmapinfo.biSizeImage << endl; - cout << " bitmapinfo.biXPelsPerMeter: " << bitmapinfo.biXPelsPerMeter << endl; - cout << " bitmapinfo.biYPelsPerMeter: " << bitmapinfo.biYPelsPerMeter << endl; - cout << " bitmapinfo.biClrUsed : " << bitmapinfo.biClrUsed << endl; - cout << " bitmapinfo.biClrImportant : " << bitmapinfo.biClrImportant << endl; - } - else if ( lastStreamType == make_fourcc( "iavs" ) ) - { - DVINFO dvinfo; - fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, &dvinfo, sizeof( DVINFO ) ) ); - cout << " dvinfo.dwDVAAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxSrc << endl; - cout << " dvinfo.dwDVAAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxCtl << endl; - cout << " dvinfo.dwDVAAuxSrc1: 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxSrc1 << endl; - cout << " dvinfo.dwDVAAuxCtl1: 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVAAuxCtl1 << endl; - cout << " dvinfo.dwDVVAuxSrc : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVVAuxSrc << endl; - cout << " dvinfo.dwDVVAuxCtl : 0x" << setw( 8 ) << setfill( '0' ) << hex << dvinfo.dwDVVAuxCtl << endl; - } - } - - /* This is the Standard Index. It is an array of offsets and - sizes relative to some start offset. */ - - else if ( ( entry.type == make_fourcc( "ix00" ) ) || ( entry.type == make_fourcc( "ix01" ) ) ) - { - - int i; - AVIStdIndex avi_std_index; - - fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, &avi_std_index, sizeof( AVIStdIndex ) ) ); - - cout << " wLongsPerEntry: " << ( int ) avi_std_index.wLongsPerEntry - << endl - << " bIndexSubType: " << ( int ) avi_std_index.bIndexSubType << endl - << " bIndexType: " << ( int ) avi_std_index.bIndexType << endl - << " nEntriesInUse: " << ( int ) avi_std_index.nEntriesInUse << endl - << " dwChunkId: '" - << ((char *)&avi_std_index.dwChunkId)[0] - << ((char *)&avi_std_index.dwChunkId)[1] - << ((char *)&avi_std_index.dwChunkId)[2] - << ((char *)&avi_std_index.dwChunkId)[3] - << '\'' << endl - << " qwBaseOffset: 0x" << setw( 12 ) << hex << avi_std_index.qwBaseOffset << endl - << " dwReserved: " << dec << ( int ) avi_std_index.dwReserved << endl; - for ( i = 0; i < avi_std_index.nEntriesInUse; ++i ) - { - cout << ' ' << setw( 4 ) << setfill( ' ' ) << i - << ": dwOffset : 0x" << setw( 8 ) << setfill( '0' ) << hex << avi_std_index.aIndex[ i ].dwOffset - << " (0x" << setw( 12 ) << avi_std_index.qwBaseOffset + avi_std_index.aIndex[ i ].dwOffset << ')' << endl - << " dwSize : 0x" << setw( 8 ) << avi_std_index.aIndex[ i ].dwSize << dec << endl; - } - - } - else if ( entry.type == make_fourcc( "idx1" ) ) - { - - int i; - int numEntries = entry.length / sizeof( int ) / 4; - DWORD *idx1 = new DWORD[ numEntries * 4 ]; - // FOURCC movi_list = FindDirectoryEntry(make_fourcc("movi")); - - fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, idx1, entry.length ) ); - - for ( i = 0; i < numEntries; ++i ) - { - - cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << setfill( '0' ) << ": dwChunkId : '" - << ((char *)&idx1[ i * 4 + 0 ])[0] - << ((char *)&idx1[ i * 4 + 0 ])[1] - << ((char *)&idx1[ i * 4 + 0 ])[2] - << ((char *)&idx1[ i * 4 + 0 ])[3] - << '\'' << endl - << " dwType : 0x" << setw( 8 ) << hex << idx1[ i * 4 + 1 ] << endl - << " dwOffset : 0x" << setw( 8 ) << idx1[ i * 4 + 2 ] << endl - // << " (0x" << setw(8) << idx1[i * 4 + 2] + GetDirectoryEntry(movi_list).offset << ')' << endl - << " dwSize : 0x" << setw( 8 ) << idx1[ i * 4 + 3 ] << dec << endl; - } - - delete[] idx1; - } - else if ( entry.type == make_fourcc( "dmlh" ) ) - { - int i; - int numEntries = entry.length / sizeof( int ); - DWORD *dmlh = new DWORD[ numEntries ]; - - fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, dmlh, entry.length ) ); - - for ( i = 0; i < numEntries; ++i ) - { - cout << ' ' << setw( 4 ) << setfill( ' ' ) << i << setfill( '0' ) << ": " - << " dwTotalFrames: 0x" << setw( 8 ) << hex << dmlh[ i ] - << " (" << dec << dmlh[ i ] << ")" << endl; - } - delete[] dmlh; - } -} - - -/** If this is not a movi list, read its contents - -*/ - -void AVIFile::ParseList( int parent ) -{ - FOURCC type; - FOURCC name; - DWORD length; - int list; - off_t pos; - off_t listEnd; - - /* Read in the chunk header (type and length). */ - fail_neg( read( fd, &type, sizeof( type ) ) ); - fail_neg( read( fd, &length, sizeof( length ) ) ); - if ( length & 1 ) - length++; - - /* The contents of the list starts here. Obtain its offset. The list - name (4 bytes) is already part of the contents). */ - - pos = lseek( fd, 0, SEEK_CUR ); - fail_if( pos == ( off_t ) - 1 ); - fail_neg( read( fd, &name, sizeof( name ) ) ); - - /* if we encounter a movi list, do not read it. It takes too much time - and we don't need it anyway. */ - - if ( name != make_fourcc( "movi" ) ) - { - // if (1) { - - /* Add an entry for this list. */ - list = AddDirectoryEntry( type, name, sizeof( name ), parent ); - - /* Read in any chunks contained in this list. This list is the - parent for all chunks it contains. */ - - listEnd = pos + length; - while ( pos < listEnd ) - { - ParseChunk( list ); - pos = lseek( fd, 0, SEEK_CUR ); - fail_if( pos == ( off_t ) - 1 ); - } - } - else - { - /* Add an entry for this list. */ - - movi_list = AddDirectoryEntry( type, name, length, parent ); - - pos = lseek( fd, length - 4, SEEK_CUR ); - fail_if( pos == ( off_t ) - 1 ); - } -} - - -void AVIFile::ParseRIFF() -{ - RIFFFile::ParseRIFF(); - - avih_chunk = FindDirectoryEntry( make_fourcc( "avih" ) ); - if ( avih_chunk != -1 ) - ReadChunk( avih_chunk, ( void* ) & mainHdr, sizeof( MainAVIHeader ) ); -} - - -void AVIFile::ReadIndex() -{ - indx_chunk[ 0 ] = FindDirectoryEntry( make_fourcc( "indx" ) ); - if ( indx_chunk[ 0 ] != -1 ) - { - ReadChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ], sizeof( AVISuperIndex ) ); - index_type = AVI_LARGE_INDEX; - - /* recalc number of frames from each index */ - mainHdr.dwTotalFrames = 0; - for ( int i = 0; - i < indx[ 0 ] ->nEntriesInUse; - mainHdr.dwTotalFrames += indx[ 0 ] ->aIndex[ i++ ].dwDuration ) - ; - return ; - } - idx1_chunk = FindDirectoryEntry( make_fourcc( "idx1" ) ); - if ( idx1_chunk != -1 ) - { - ReadChunk( idx1_chunk, ( void* ) idx1, sizeof( AVISuperIndex ) ); - idx1->nEntriesInUse = GetDirectoryEntry( idx1_chunk ).length / 16; - index_type = AVI_SMALL_INDEX; - - /* recalc number of frames from the simple index */ - int frameNumIndex = 0; - FOURCC chunkID1 = make_fourcc( "00dc" ); - FOURCC chunkID2 = make_fourcc( "00db" ); - for ( int i = 0; i < idx1->nEntriesInUse; ++i ) - { - if ( idx1->aIndex[ i ].dwChunkId == chunkID1 || - idx1->aIndex[ i ].dwChunkId == chunkID2 ) - { - ++frameNumIndex; - } - } - mainHdr.dwTotalFrames = frameNumIndex; - return ; - } -} - - -void AVIFile::FlushIndx( int stream ) -{ - FOURCC type; - FOURCC name; - off_t length; - off_t offset; - int parent; - int i; - - /* Write out the previous index. When this function is - entered for the first time, there is no index to - write. Note: this may be an expensive operation - because of a time consuming seek to the former file - position. */ - - if ( ix_chunk[ stream ] != -1 ) - WriteChunk( ix_chunk[ stream ], ix[ stream ] ); - - /* make a new ix chunk. */ - - if ( stream == 0 ) - type = make_fourcc( "ix00" ); - else - type = make_fourcc( "ix01" ); - ix_chunk[ stream ] = AddDirectoryEntry( type, 0, sizeof( AVIStdIndex ), movi_list ); - GetDirectoryEntry( ix_chunk[ stream ], type, name, length, offset, parent ); - - /* fill out all required fields. The offsets in the - array are relative to qwBaseOffset, so fill in the - offset to the next free location in the file - there. */ - - ix[ stream ] ->wLongsPerEntry = 2; - ix[ stream ] ->bIndexSubType = 0; - ix[ stream ] ->bIndexType = KINO_AVI_INDEX_OF_CHUNKS; - ix[ stream ] ->nEntriesInUse = 0; - ix[ stream ] ->dwChunkId = indx[ stream ] ->dwChunkId; - ix[ stream ] ->qwBaseOffset = offset + length; - ix[ stream ] ->dwReserved = 0; - - for ( i = 0; i < IX00_INDEX_SIZE; ++i ) - { - ix[ stream ] ->aIndex[ i ].dwOffset = 0; - ix[ stream ] ->aIndex[ i ].dwSize = 0; - } - - /* add a reference to this new index in our super - index. */ - - i = indx[ stream ] ->nEntriesInUse++; - indx[ stream ] ->aIndex[ i ].qwOffset = offset - RIFF_HEADERSIZE; - indx[ stream ] ->aIndex[ i ].dwSize = length + RIFF_HEADERSIZE; - indx[ stream ] ->aIndex[ i ].dwDuration = 0; -} - - -void AVIFile::UpdateIndx( int stream, int chunk, int duration ) -{ - FOURCC type; - FOURCC name; - off_t length; - off_t offset; - int parent; - int i; - - /* update the appropriate entry in the super index. It reflects - the number of frames in the referenced index. */ - - i = indx[ stream ] ->nEntriesInUse - 1; - indx[ stream ] ->aIndex[ i ].dwDuration += duration; - - /* update the standard index. Calculate the file position of - the new frame. */ - - GetDirectoryEntry( chunk, type, name, length, offset, parent ); - - indx[ stream ] ->dwChunkId = type; - i = ix[ stream ] ->nEntriesInUse++; - ix[ stream ] ->aIndex[ i ].dwOffset = offset - ix[ stream ] ->qwBaseOffset; - ix[ stream ] ->aIndex[ i ].dwSize = length; -} - - -void AVIFile::UpdateIdx1( int chunk, int flags ) -{ - if ( idx1->nEntriesInUse < 20000 ) - { - FOURCC type; - FOURCC name; - off_t length; - off_t offset; - int parent; - - GetDirectoryEntry( chunk, type, name, length, offset, parent ); - - idx1->aIndex[ idx1->nEntriesInUse ].dwChunkId = type; - idx1->aIndex[ idx1->nEntriesInUse ].dwFlags = flags; - idx1->aIndex[ idx1->nEntriesInUse ].dwOffset = offset - GetDirectoryEntry( movi_list ).offset - RIFF_HEADERSIZE; - idx1->aIndex[ idx1->nEntriesInUse ].dwSize = length; - idx1->nEntriesInUse++; - } -} - -bool AVIFile::verifyStreamFormat( FOURCC type ) -{ - int i, j = 0; - AVIStreamHeader avi_stream_header; - BITMAPINFOHEADER bih; - FOURCC strh = make_fourcc( "strh" ); - FOURCC strf = make_fourcc( "strf" ); - - while ( ( i = FindDirectoryEntry( strh, j++ ) ) != -1 ) - { - ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) ); - if ( avi_stream_header.fccHandler == type ) - return true; - } - j = 0; - while ( ( i = FindDirectoryEntry( strf, j++ ) ) != -1 ) - { - ReadChunk( i, ( void* ) & bih, sizeof( BITMAPINFOHEADER ) ); - if ( ( FOURCC ) bih.biCompression == type ) - return true; - } - - return false; -} - -bool AVIFile::verifyStream( FOURCC type ) -{ - int i, j = 0; - AVIStreamHeader avi_stream_header; - FOURCC strh = make_fourcc( "strh" ); - - while ( ( i = FindDirectoryEntry( strh, j++ ) ) != -1 ) - { - ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) ); - if ( avi_stream_header.fccType == type ) - return true; - } - return false; -} - -bool AVIFile::isOpenDML( void ) -{ - int i, j = 0; - FOURCC dmlh = make_fourcc( "dmlh" ); - - while ( ( i = FindDirectoryEntry( dmlh, j++ ) ) != -1 ) - { - return true; - } - return false; -} - -AVI1File::AVI1File() : AVIFile() -{ - memset( &dvinfo, 0, sizeof( dvinfo ) ); -} - - -AVI1File::~AVI1File() -{} - - -/* Initialize the AVI structure to its initial state, either for PAL - or NTSC format */ - -void AVI1File::Init( int format, int sampleFrequency, int indexType ) -{ - int num_blocks; - FOURCC type; - FOURCC name; - off_t length; - off_t offset; - int parent; - - assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) ); - - AVIFile::Init( format, sampleFrequency, indexType ); - - switch ( format ) - { - case AVI_PAL: - mainHdr.dwWidth = 720; - mainHdr.dwHeight = 576; - - streamHdr[ 0 ].dwScale = 1; - streamHdr[ 0 ].dwRate = 25; - streamHdr[ 0 ].dwSuggestedBufferSize = 144008; - - /* initialize the 'strf' chunk */ - - /* Meaning of the DV stream format chunk per Microsoft - dwDVAAuxSrc - Specifies the Audio Auxiliary Data Source Pack for the first audio block - (first 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of - a frame. A DIF sequence is a data block that contains 150 DIF blocks. A DIF block consists - of 80 bytes. The Audio Auxiliary Data Source Pack is defined in section D.7.1 of Part 2, - Annex D, "The Pack Header Table and Contents of Packs" of the Specification of - Consumer-use Digital VCRs. - dwDVAAuxCtl - Specifies the Audio Auxiliary Data Source Control Pack for the first audio block of a - frame. The Audio Auxiliary Data Control Pack is defined in section D.7.2 of Part 2, - Annex D, "The Pack Header Table and Contents of Packs" of the Specification of - Consumer-use Digital VCRs. - dwDVAAuxSrc1 - Specifies the Audio Auxiliary Data Source Pack for the second audio block - (second 5 DV DIF sequences for 525-60 systems or 6 DV DIF sequences for 625-50 systems) of a frame. - dwDVAAuxCtl1 - Specifies the Audio Auxiliary Data Source Control Pack for the second audio block of a frame. - dwDVVAuxSrc - Specifies the Video Auxiliary Data Source Pack as defined in section D.8.1 of Part 2, - Annex D, "The Pack Header Table and Contents of Packs" of the Specification of - Consumer-use Digital VCRs. - dwDVVAuxCtl - Specifies the Video Auxiliary Data Source Control Pack as defined in section D.8.2 of Part 2, - Annex D, "The Pack Header Table and Contents of Packs" of the Specification of - Consumer-use Digital VCRs. - dwDVReserved[2] - Reserved. Set this array to zero. - */ - - dvinfo.dwDVAAuxSrc = 0xd1e030d0; - dvinfo.dwDVAAuxCtl = 0xffa0cf3f; - dvinfo.dwDVAAuxSrc1 = 0xd1e03fd0; - dvinfo.dwDVAAuxCtl1 = 0xffa0cf3f; - dvinfo.dwDVVAuxSrc = 0xff20ffff; - dvinfo.dwDVVAuxCtl = 0xfffdc83f; - dvinfo.dwDVReserved[ 0 ] = 0; - dvinfo.dwDVReserved[ 1 ] = 0; - break; - - case AVI_NTSC: - mainHdr.dwWidth = 720; - mainHdr.dwHeight = 480; - - streamHdr[ 0 ].dwScale = 1001; - streamHdr[ 0 ].dwRate = 30000; - streamHdr[ 0 ].dwSuggestedBufferSize = 120008; - - /* initialize the 'strf' chunk */ - dvinfo.dwDVAAuxSrc = 0xc0c000c0; - dvinfo.dwDVAAuxCtl = 0xffa0cf3f; - dvinfo.dwDVAAuxSrc1 = 0xc0c001c0; - dvinfo.dwDVAAuxCtl1 = 0xffa0cf3f; - dvinfo.dwDVVAuxSrc = 0xff80ffff; - dvinfo.dwDVVAuxCtl = 0xfffcc83f; - dvinfo.dwDVReserved[ 0 ] = 0; - dvinfo.dwDVReserved[ 1 ] = 0; - break; - - default: /* no default allowed */ - assert( 0 ); - break; - } - - indx[ 0 ] ->dwChunkId = make_fourcc( "00__" ); - - /* Initialize the 'strh' chunk */ - - streamHdr[ 0 ].fccType = make_fourcc( "iavs" ); - streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" ); - streamHdr[ 0 ].dwFlags = 0; - streamHdr[ 0 ].wPriority = 0; - streamHdr[ 0 ].wLanguage = 0; - streamHdr[ 0 ].dwInitialFrames = 0; - streamHdr[ 0 ].dwStart = 0; - streamHdr[ 0 ].dwLength = 0; - streamHdr[ 0 ].dwQuality = 0; - streamHdr[ 0 ].dwSampleSize = 0; - streamHdr[ 0 ].rcFrame.top = 0; - streamHdr[ 0 ].rcFrame.bottom = 0; - streamHdr[ 0 ].rcFrame.left = 0; - streamHdr[ 0 ].rcFrame.right = 0; - - /* This is a simple directory structure setup. For details see the - "OpenDML AVI File Format Extensions" document. - - An AVI file contains basically two types of objects, a - "chunk" and a "list" object. The list object contains any - number of chunks. Since a list is also a chunk, it is - possible to create a hierarchical "list of lists" - structure. - - Every AVI file starts with a "RIFF" object, which is a list - of several other required objects. The actual DV data is - contained in a "movi" list, each frame is in its own chunk. - - Old AVI files (pre OpenDML V. 1.02) contain only one RIFF - chunk of less than 1 GByte size per file. The current - format which allow for almost arbitrary sizes can contain - several RIFF chunks of less than 1 GByte size. Old software - however would only deal with the first RIFF chunk. - - Note that the first entry (FILE) isn�t actually part - of the AVI file. I use this (pseudo-) directory entry to - keep track of the RIFF chunks and their positions in the - AVI file. - */ - - /* Create the container directory entry */ - - file_list = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT ); - - /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */ - - riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE, file_list ); - hdrl_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE, riff_list ); - avih_chunk = AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader ), hdrl_list ); - strl_list[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list ); - strh_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 0 ] ); - strf_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( dvinfo ), strl_list[ 0 ] ); - if ( index_type & AVI_LARGE_INDEX ) - indx_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 0 ] ); - - odml_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE, hdrl_list ); - dmlh_chunk = AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list ); - - /* align movi list to block */ - GetDirectoryEntry( hdrl_list, type, name, length, offset, parent ); - num_blocks = length / PADDING_SIZE + 1; - length = num_blocks * PADDING_SIZE - length - 5 * RIFF_HEADERSIZE; // why 5? - junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list ); - - movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list ); - - /* The ix00 chunk will be added dynamically to the movi_list in avi_write_frame - as needed */ - - ix_chunk[ 0 ] = -1; -} - - -/* Write a DV video frame. This is somewhat complex... */ - -#if 0 -bool AVI1File::WriteFrame( const Frame &frame ) -{ - int frame_chunk; - int junk_chunk; - int num_blocks; - FOURCC type; - FOURCC name; - off_t length; - off_t offset; - int parent; - - /* exit if no large index and 1GB reached */ - if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false ) - return false; - - /* Check if we need a new ix00 Standard Index. It has a - capacity of IX00_INDEX_SIZE frames. Whenever we exceed that - number, we need a new index. The new ix00 chunk is also - part of the movi list. */ - - if ( ( index_type & AVI_LARGE_INDEX ) && ( ( ( streamHdr[ 0 ].dwLength - 0 ) % IX00_INDEX_SIZE ) == 0 ) ) - FlushIndx( 0 ); - - /* Write the DV frame data. - - Make a new 00__ chunk for the new frame, write out the - frame. */ - - frame_chunk = AddDirectoryEntry( make_fourcc( "00__" ), 0, frame.GetFrameSize(), movi_list ); - if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 ) - { - GetDirectoryEntry( frame_chunk, type, name, length, offset, parent ); - ix[ 0 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE; - } - WriteChunk( frame_chunk, frame.data ); - // num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1; - // length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE; - // junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list); - // WriteChunk(junk_chunk, g_zeroes); - - if ( index_type & AVI_LARGE_INDEX ) - UpdateIndx( 0, frame_chunk, 1 ); - if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) - UpdateIdx1( frame_chunk, 0x10 ); - - /* update some variables with the new frame count. */ - - if ( isUpdateIdx1 ) - ++mainHdr.dwTotalFrames; - ++streamHdr[ 0 ].dwLength; - ++dmlh[ 0 ]; - - /* Find out if the current riff list is close to 1 GByte in - size. If so, start a new (extended) RIFF. The only allowed - item in the new RIFF chunk is a movi list (with video - frames and indexes as usual). */ - - GetDirectoryEntry( riff_list, type, name, length, offset, parent ); - if ( length > 0x3f000000 ) - { - /* write idx1 only once and before end of first GB */ - if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) - { - int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list ); - WriteChunk( idx1_chunk, ( void* ) idx1 ); - } - isUpdateIdx1 = false; - - if ( index_type & AVI_LARGE_INDEX ) - { - /* pad out to 1GB */ - //GetDirectoryEntry(riff_list, type, name, length, offset, parent); - //junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, PADDING_1GB - length - 5 * RIFF_HEADERSIZE, riff_list); - //WriteChunk(junk_chunk, g_zeroes); - - /* padding for alignment */ - GetDirectoryEntry( riff_list, type, name, length, offset, parent ); - num_blocks = ( length + 4 * RIFF_HEADERSIZE ) / PADDING_SIZE + 1; - length = ( num_blocks * PADDING_SIZE ) - length - 4 * RIFF_HEADERSIZE - 2 * RIFF_LISTSIZE; - if ( length > 0 ) - { - junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list ); - WriteChunk( junk_chunk, g_zeroes ); - } - - riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE, file_list ); - movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list ); - } - } - return true; -} -#endif - -void AVI1File::WriteRIFF() -{ - - WriteChunk( avih_chunk, ( void* ) & mainHdr ); - WriteChunk( strh_chunk[ 0 ], ( void* ) & streamHdr[ 0 ] ); - WriteChunk( strf_chunk[ 0 ], ( void* ) & dvinfo ); - WriteChunk( dmlh_chunk, ( void* ) & dmlh ); - - if ( index_type & AVI_LARGE_INDEX ) - { - WriteChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ] ); - WriteChunk( ix_chunk[ 0 ], ( void* ) ix[ 0 ] ); - } - - if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) - { - int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list ); - WriteChunk( idx1_chunk, ( void* ) idx1 ); - } - - RIFFFile::WriteRIFF(); -} - - -AVI2File::AVI2File() : AVIFile() -{} - - -AVI2File::~AVI2File() -{} - - -/* Initialize the AVI structure to its initial state, either for PAL - or NTSC format */ - -void AVI2File::Init( int format, int sampleFrequency, int indexType ) -{ - int num_blocks; - FOURCC type; - FOURCC name; - off_t length; - off_t offset; - int parent; - - assert( ( format == AVI_PAL ) || ( format == AVI_NTSC ) ); - - AVIFile::Init( format, sampleFrequency, indexType ); - - switch ( format ) - { - - case AVI_PAL: - mainHdr.dwStreams = 2; - mainHdr.dwWidth = 720; - mainHdr.dwHeight = 576; - - /* Initialize the 'strh' chunk */ - - streamHdr[ 0 ].fccType = make_fourcc( "vids" ); - streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" ); - streamHdr[ 0 ].dwFlags = 0; - streamHdr[ 0 ].wPriority = 0; - streamHdr[ 0 ].wLanguage = 0; - streamHdr[ 0 ].dwInitialFrames = 0; - streamHdr[ 0 ].dwScale = 1; - streamHdr[ 0 ].dwRate = 25; - streamHdr[ 0 ].dwStart = 0; - streamHdr[ 0 ].dwLength = 0; - streamHdr[ 0 ].dwSuggestedBufferSize = 144008; - streamHdr[ 0 ].dwQuality = -1; - streamHdr[ 0 ].dwSampleSize = 0; - streamHdr[ 0 ].rcFrame.top = 0; - streamHdr[ 0 ].rcFrame.bottom = 0; - streamHdr[ 0 ].rcFrame.left = 0; - streamHdr[ 0 ].rcFrame.right = 0; - - bitmapinfo.biSize = sizeof( bitmapinfo ); - bitmapinfo.biWidth = 720; - bitmapinfo.biHeight = 576; - bitmapinfo.biPlanes = 1; - bitmapinfo.biBitCount = 24; - bitmapinfo.biCompression = make_fourcc( "dvsd" ); - bitmapinfo.biSizeImage = 144000; - bitmapinfo.biXPelsPerMeter = 0; - bitmapinfo.biYPelsPerMeter = 0; - bitmapinfo.biClrUsed = 0; - bitmapinfo.biClrImportant = 0; - - streamHdr[ 1 ].fccType = make_fourcc( "auds" ); - streamHdr[ 1 ].fccHandler = 0; - streamHdr[ 1 ].dwFlags = 0; - streamHdr[ 1 ].wPriority = 0; - streamHdr[ 1 ].wLanguage = 0; - streamHdr[ 1 ].dwInitialFrames = 0; - streamHdr[ 1 ].dwScale = 2 * 2; - streamHdr[ 1 ].dwRate = sampleFrequency * 2 * 2; - streamHdr[ 1 ].dwStart = 0; - streamHdr[ 1 ].dwLength = 0; - streamHdr[ 1 ].dwSuggestedBufferSize = 8192; - streamHdr[ 1 ].dwQuality = -1; - streamHdr[ 1 ].dwSampleSize = 2 * 2; - streamHdr[ 1 ].rcFrame.top = 0; - streamHdr[ 1 ].rcFrame.bottom = 0; - streamHdr[ 1 ].rcFrame.left = 0; - streamHdr[ 1 ].rcFrame.right = 0; - - break; - - case AVI_NTSC: - mainHdr.dwTotalFrames = 0; - mainHdr.dwStreams = 2; - mainHdr.dwWidth = 720; - mainHdr.dwHeight = 480; - - /* Initialize the 'strh' chunk */ - - streamHdr[ 0 ].fccType = make_fourcc( "vids" ); - streamHdr[ 0 ].fccHandler = make_fourcc( "dvsd" ); - streamHdr[ 0 ].dwFlags = 0; - streamHdr[ 0 ].wPriority = 0; - streamHdr[ 0 ].wLanguage = 0; - streamHdr[ 0 ].dwInitialFrames = 0; - streamHdr[ 0 ].dwScale = 1001; - streamHdr[ 0 ].dwRate = 30000; - streamHdr[ 0 ].dwStart = 0; - streamHdr[ 0 ].dwLength = 0; - streamHdr[ 0 ].dwSuggestedBufferSize = 120008; - streamHdr[ 0 ].dwQuality = -1; - streamHdr[ 0 ].dwSampleSize = 0; - streamHdr[ 0 ].rcFrame.top = 0; - streamHdr[ 0 ].rcFrame.bottom = 0; - streamHdr[ 0 ].rcFrame.left = 0; - streamHdr[ 0 ].rcFrame.right = 0; - - bitmapinfo.biSize = sizeof( bitmapinfo ); - bitmapinfo.biWidth = 720; - bitmapinfo.biHeight = 480; - bitmapinfo.biPlanes = 1; - bitmapinfo.biBitCount = 24; - bitmapinfo.biCompression = make_fourcc( "dvsd" ); - bitmapinfo.biSizeImage = 120000; - bitmapinfo.biXPelsPerMeter = 0; - bitmapinfo.biYPelsPerMeter = 0; - bitmapinfo.biClrUsed = 0; - bitmapinfo.biClrImportant = 0; - - streamHdr[ 1 ].fccType = make_fourcc( "auds" ); - streamHdr[ 1 ].fccHandler = 0; - streamHdr[ 1 ].dwFlags = 0; - streamHdr[ 1 ].wPriority = 0; - streamHdr[ 1 ].wLanguage = 0; - streamHdr[ 1 ].dwInitialFrames = 1; - streamHdr[ 1 ].dwScale = 2 * 2; - streamHdr[ 1 ].dwRate = sampleFrequency * 2 * 2; - streamHdr[ 1 ].dwStart = 0; - streamHdr[ 1 ].dwLength = 0; - streamHdr[ 1 ].dwSuggestedBufferSize = 8192; - streamHdr[ 1 ].dwQuality = 0; - streamHdr[ 1 ].dwSampleSize = 2 * 2; - streamHdr[ 1 ].rcFrame.top = 0; - streamHdr[ 1 ].rcFrame.bottom = 0; - streamHdr[ 1 ].rcFrame.left = 0; - streamHdr[ 1 ].rcFrame.right = 0; - - break; - } - waveformatex.wFormatTag = 1; - waveformatex.nChannels = 2; - waveformatex.nSamplesPerSec = sampleFrequency; - waveformatex.nAvgBytesPerSec = sampleFrequency * 2 * 2; - waveformatex.nBlockAlign = 4; - waveformatex.wBitsPerSample = 16; - waveformatex.cbSize = 0; - - file_list = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT ); - - /* Create a basic directory structure. Only chunks defined from here on will be written to the AVI file. */ - - riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVI " ), RIFF_LISTSIZE, file_list ); - hdrl_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "hdrl" ), RIFF_LISTSIZE, riff_list ); - avih_chunk = AddDirectoryEntry( make_fourcc( "avih" ), 0, sizeof( MainAVIHeader ), hdrl_list ); - - strl_list[ 0 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list ); - strh_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 0 ] ); - strf_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( BITMAPINFOHEADER ), strl_list[ 0 ] ); - if ( index_type & AVI_LARGE_INDEX ) - { - indx_chunk[ 0 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 0 ] ); - ix_chunk[ 0 ] = -1; - indx[ 0 ] ->dwChunkId = make_fourcc( "00dc" ); - } - - strl_list[ 1 ] = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "strl" ), RIFF_LISTSIZE, hdrl_list ); - strh_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "strh" ), 0, sizeof( AVIStreamHeader ), strl_list[ 1 ] ); - strf_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "strf" ), 0, sizeof( WAVEFORMATEX ) - 2, strl_list[ 1 ] ); - junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, 2, strl_list[ 1 ] ); - if ( index_type & AVI_LARGE_INDEX ) - { - indx_chunk[ 1 ] = AddDirectoryEntry( make_fourcc( "indx" ), 0, sizeof( AVISuperIndex ), strl_list[ 1 ] ); - ix_chunk[ 1 ] = -1; - indx[ 1 ] ->dwChunkId = make_fourcc( "01wb" ); - - odml_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "odml" ), RIFF_LISTSIZE, hdrl_list ); - dmlh_chunk = AddDirectoryEntry( make_fourcc( "dmlh" ), 0, 0x00f8, odml_list ); - } - - /* align movi list to block */ - GetDirectoryEntry( hdrl_list, type, name, length, offset, parent ); - num_blocks = length / PADDING_SIZE + 1; - length = num_blocks * PADDING_SIZE - length - 5 * RIFF_HEADERSIZE; // why 5 headers? - junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list ); - - movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list ); - - idx1->aIndex[ idx1->nEntriesInUse ].dwChunkId = make_fourcc( "7Fxx" ); - idx1->aIndex[ idx1->nEntriesInUse ].dwFlags = 0; - idx1->aIndex[ idx1->nEntriesInUse ].dwOffset = 0; - idx1->aIndex[ idx1->nEntriesInUse ].dwSize = 0; - idx1->nEntriesInUse++; -} - - -void AVI2File::WriteRIFF() -{ - WriteChunk( avih_chunk, ( void* ) & mainHdr ); - WriteChunk( strh_chunk[ 0 ], ( void* ) & streamHdr[ 0 ] ); - WriteChunk( strf_chunk[ 0 ], ( void* ) & bitmapinfo ); - if ( index_type & AVI_LARGE_INDEX ) - { - WriteChunk( dmlh_chunk, ( void* ) & dmlh ); - WriteChunk( indx_chunk[ 0 ], ( void* ) indx[ 0 ] ); - WriteChunk( ix_chunk[ 0 ], ( void* ) ix[ 0 ] ); - } - WriteChunk( strh_chunk[ 1 ], ( void* ) & streamHdr[ 1 ] ); - WriteChunk( strf_chunk[ 1 ], ( void* ) & waveformatex ); - if ( index_type & AVI_LARGE_INDEX ) - { - WriteChunk( indx_chunk[ 1 ], ( void* ) indx[ 1 ] ); - WriteChunk( ix_chunk[ 1 ], ( void* ) ix[ 1 ] ); - } - - if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) - { - int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list ); - WriteChunk( idx1_chunk, ( void* ) idx1 ); - } - RIFFFile::WriteRIFF(); -} - - -/** Write a DV video frame - - \param frame the frame to write -*/ - -#if 0 -bool AVI2File::WriteFrame( const Frame &frame ) -{ - int audio_chunk; - int frame_chunk; - int junk_chunk; - char soundbuf[ 20000 ]; - int audio_size; - int num_blocks; - FOURCC type; - FOURCC name; - off_t length; - off_t offset; - int parent; - - /* exit if no large index and 1GB reached */ - if ( !( index_type & AVI_LARGE_INDEX ) && isUpdateIdx1 == false ) - return false; - - /* Check if we need a new ix00 Standard Index. It has a - capacity of IX00_INDEX_SIZE frames. Whenever we exceed that - number, we need a new index. The new ix00 chunk is also - part of the movi list. */ - - if ( ( index_type & AVI_LARGE_INDEX ) && ( ( ( streamHdr[ 0 ].dwLength - 0 ) % IX00_INDEX_SIZE ) == 0 ) ) - { - FlushIndx( 0 ); - FlushIndx( 1 ); - } - - /* Write audio data if we have it */ - - audio_size = frame.ExtractAudio( soundbuf ); - if ( audio_size > 0 ) - { - audio_chunk = AddDirectoryEntry( make_fourcc( "01wb" ), 0, audio_size, movi_list ); - if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 ) - { - GetDirectoryEntry( audio_chunk, type, name, length, offset, parent ); - ix[ 1 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE; - } - WriteChunk( audio_chunk, soundbuf ); - // num_blocks = (audio_size + RIFF_HEADERSIZE) / PADDING_SIZE + 1; - // length = num_blocks * PADDING_SIZE - audio_size - 2 * RIFF_HEADERSIZE; - // junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list); - // WriteChunk(junk_chunk, g_zeroes); - if ( index_type & AVI_LARGE_INDEX ) - UpdateIndx( 1, audio_chunk, audio_size / waveformatex.nChannels / 2 ); - if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) - UpdateIdx1( audio_chunk, 0x00 ); - streamHdr[ 1 ].dwLength += audio_size / waveformatex.nChannels / 2; - - } - - /* Write video data */ - - frame_chunk = AddDirectoryEntry( make_fourcc( "00dc" ), 0, frame.GetFrameSize(), movi_list ); - if ( ( index_type & AVI_LARGE_INDEX ) && ( streamHdr[ 0 ].dwLength % IX00_INDEX_SIZE ) == 0 ) - { - GetDirectoryEntry( frame_chunk, type, name, length, offset, parent ); - ix[ 0 ] ->qwBaseOffset = offset - RIFF_HEADERSIZE; - } - WriteChunk( frame_chunk, frame.data ); - // num_blocks = (frame.GetFrameSize() + RIFF_HEADERSIZE) / PADDING_SIZE + 1; - // length = num_blocks * PADDING_SIZE - frame.GetFrameSize() - 2 * RIFF_HEADERSIZE; - // junk_chunk = AddDirectoryEntry(make_fourcc("JUNK"), 0, length, movi_list); - // WriteChunk(junk_chunk, g_zeroes); - if ( index_type & AVI_LARGE_INDEX ) - UpdateIndx( 0, frame_chunk, 1 ); - if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) - UpdateIdx1( frame_chunk, 0x10 ); - - /* update some variables with the new frame count. */ - - if ( isUpdateIdx1 ) - ++mainHdr.dwTotalFrames; - ++streamHdr[ 0 ].dwLength; - ++dmlh[ 0 ]; - - /* Find out if the current riff list is close to 1 GByte in - size. If so, start a new (extended) RIFF. The only allowed - item in the new RIFF chunk is a movi list (with video - frames and indexes as usual). */ - - GetDirectoryEntry( riff_list, type, name, length, offset, parent ); - if ( length > 0x3f000000 ) - { - - /* write idx1 only once and before end of first GB */ - if ( ( index_type & AVI_SMALL_INDEX ) && isUpdateIdx1 ) - { - int idx1_chunk = AddDirectoryEntry( make_fourcc( "idx1" ), 0, idx1->nEntriesInUse * 16, riff_list ); - WriteChunk( idx1_chunk, ( void* ) idx1 ); - } - isUpdateIdx1 = false; - - if ( index_type & AVI_LARGE_INDEX ) - { - /* padding for alignment */ - GetDirectoryEntry( riff_list, type, name, length, offset, parent ); - num_blocks = ( length + 4 * RIFF_HEADERSIZE ) / PADDING_SIZE + 1; - length = ( num_blocks * PADDING_SIZE ) - length - 4 * RIFF_HEADERSIZE - 2 * RIFF_LISTSIZE; - if ( length > 0 ) - { - junk_chunk = AddDirectoryEntry( make_fourcc( "JUNK" ), 0, length, riff_list ); - WriteChunk( junk_chunk, g_zeroes ); - } - - riff_list = AddDirectoryEntry( make_fourcc( "RIFF" ), make_fourcc( "AVIX" ), RIFF_LISTSIZE, file_list ); - movi_list = AddDirectoryEntry( make_fourcc( "LIST" ), make_fourcc( "movi" ), RIFF_LISTSIZE, riff_list ); - } - } - return true; -} -#endif - -void AVI1File::setDVINFO( DVINFO &info ) -{ - // do not do this until debugged audio against DirectShow - return ; - - dvinfo.dwDVAAuxSrc = info.dwDVAAuxSrc; - dvinfo.dwDVAAuxCtl = info.dwDVAAuxCtl; - dvinfo.dwDVAAuxSrc1 = info.dwDVAAuxSrc1; - dvinfo.dwDVAAuxCtl1 = info.dwDVAAuxCtl1; - dvinfo.dwDVVAuxSrc = info.dwDVVAuxSrc; - dvinfo.dwDVVAuxCtl = info.dwDVVAuxCtl; -} - - -void AVI2File::setDVINFO( DVINFO &info ) -{} - -void AVIFile::setFccHandler( FOURCC type, FOURCC handler ) -{ - for ( int i = 0; i < mainHdr.dwStreams; i++ ) - { - if ( streamHdr[ i ].fccType == type ) - { - int k, j = 0; - FOURCC strf = make_fourcc( "strf" ); - BITMAPINFOHEADER bih; - - streamHdr[ i ].fccHandler = handler; - - while ( ( k = FindDirectoryEntry( strf, j++ ) ) != -1 ) - { - ReadChunk( k, ( void* ) & bih, sizeof( BITMAPINFOHEADER ) ); - bih.biCompression = handler; - } - } - } -} - -bool AVIFile::getStreamFormat( void* data, FOURCC type ) -{ - int i, j = 0; - FOURCC strh = make_fourcc( "strh" ); - FOURCC strf = make_fourcc( "strf" ); - AVIStreamHeader avi_stream_header; - bool result = false; - - while ( ( result == false ) && ( i = FindDirectoryEntry( strh, j++ ) ) != -1 ) - { - ReadChunk( i, ( void* ) & avi_stream_header, sizeof( AVIStreamHeader ) ); - if ( avi_stream_header.fccType == type ) - { - FOURCC chunkID; - int size; - - pthread_mutex_lock( &file_mutex ); - fail_neg( read( fd, &chunkID, sizeof( FOURCC ) ) ); - if ( chunkID == strf ) - { - fail_neg( read( fd, &size, sizeof( int ) ) ); - fail_neg( read( fd, data, size ) ); - result = true; - } - pthread_mutex_unlock( &file_mutex ); - } - } - return result; -} diff --git a/src/modules/kino/avi.h b/src/modules/kino/avi.h deleted file mode 100644 index 6c20923bc..000000000 --- a/src/modules/kino/avi.h +++ /dev/null @@ -1,330 +0,0 @@ -/* -* avi.h library for AVI file format i/o -* Copyright (C) 2000 - 2002 Arne Schirmacher -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -/** Common AVI declarations - - Some of this comes from the public domain AVI specification, which - explains the microsoft-style definitions. - - \file avi.h -*/ - -#ifndef _AVI_H -#define _AVI_H 1 - -#include -#include "riff.h" - -#define PACKED(x) __attribute__((packed)) x - -#define AVI_SMALL_INDEX (0x01) -#define AVI_LARGE_INDEX (0x02) -#define KINO_AVI_INDEX_OF_INDEXES (0x00) -#define KINO_AVI_INDEX_OF_CHUNKS (0x01) -#define AVI_INDEX_2FIELD (0x01) - -enum { AVI_PAL, AVI_NTSC, AVI_AUDIO_48KHZ, AVI_AUDIO_44KHZ, AVI_AUDIO_32KHZ }; - -/** Declarations of the main AVI file header - - The contents of this struct goes into the 'avih' chunk. */ - -typedef struct -{ - /// frame display rate (or 0L) - DWORD dwMicroSecPerFrame; - - /// max. transfer rate - DWORD dwMaxBytesPerSec; - - /// pad to multiples of this size, normally 2K - DWORD dwPaddingGranularity; - - /// the ever-present flags - DWORD dwFlags; - - /// # frames in file - DWORD dwTotalFrames; - DWORD dwInitialFrames; - DWORD dwStreams; - DWORD dwSuggestedBufferSize; - - DWORD dwWidth; - DWORD dwHeight; - - DWORD dwReserved[ 4 ]; -} -PACKED(MainAVIHeader); - -typedef struct -{ - WORD top, bottom, left, right; -} -PACKED(RECT); - -/** Declaration of a stream header - - The contents of this struct goes into the 'strh' header. */ - -typedef struct -{ - FOURCC fccType; - FOURCC fccHandler; - DWORD dwFlags; /* Contains AVITF_* flags */ - WORD wPriority; - WORD wLanguage; - DWORD dwInitialFrames; - DWORD dwScale; - DWORD dwRate; /* dwRate / dwScale == samples/second */ - DWORD dwStart; - DWORD dwLength; /* In units above... */ - DWORD dwSuggestedBufferSize; - DWORD dwQuality; - DWORD dwSampleSize; - RECT rcFrame; -} -PACKED(AVIStreamHeader); - -typedef struct -{ - DWORD dwDVAAuxSrc; - DWORD dwDVAAuxCtl; - DWORD dwDVAAuxSrc1; - DWORD dwDVAAuxCtl1; - DWORD dwDVVAuxSrc; - DWORD dwDVVAuxCtl; - DWORD dwDVReserved[ 2 ]; -} -PACKED(DVINFO); - -typedef struct -{ - DWORD biSize; - LONG biWidth; - LONG biHeight; - WORD biPlanes; - WORD biBitCount; - DWORD biCompression; - DWORD biSizeImage; - LONG biXPelsPerMeter; - LONG biYPelsPerMeter; - DWORD biClrUsed; - DWORD biClrImportant; - char dummy[ 1040 ]; -} -PACKED(BITMAPINFOHEADER); - -typedef struct -{ - WORD wFormatTag; - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nAvgBytesPerSec; - WORD nBlockAlign; - WORD wBitsPerSample; - WORD cbSize; - WORD dummy; -} -PACKED(WAVEFORMATEX); - -typedef struct -{ - WORD wLongsPerEntry; - BYTE bIndexSubType; - BYTE bIndexType; - DWORD nEntriesInUse; - FOURCC dwChunkId; - DWORD dwReserved[ 3 ]; - struct avisuperindex_entry - { - QUADWORD qwOffset; - DWORD dwSize; - DWORD dwDuration; - } - aIndex[ 3198 ]; -} -PACKED(AVISuperIndex); - -typedef struct -{ - WORD wLongsPerEntry; - BYTE bIndexSubType; - BYTE bIndexType; - DWORD nEntriesInUse; - FOURCC dwChunkId; - QUADWORD qwBaseOffset; - DWORD dwReserved; - struct avifieldindex_entry - { - DWORD dwOffset; - DWORD dwSize; - } - aIndex[ 17895 ]; -} -PACKED(AVIStdIndex); - -typedef struct -{ - struct avisimpleindex_entry - { - FOURCC dwChunkId; - DWORD dwFlags; - DWORD dwOffset; - DWORD dwSize; - } - aIndex[ 20000 ]; - DWORD nEntriesInUse; -} -PACKED(AVISimpleIndex); - -typedef struct -{ - DWORD dirEntryType; - DWORD dirEntryName; - DWORD dirEntryLength; - size_t dirEntryOffset; - int dirEntryWrittenFlag; - int dirEntryParentList; -} -AviDirEntry; - - -/** base class for all AVI type files - - It contains methods and members which are the same in all AVI type files regardless of the particular compression, number - of streams etc. - - The AVIFile class also contains methods for handling several indexes to the video frame content. */ - -class AVIFile : public RIFFFile -{ -public: - AVIFile(); - AVIFile( const AVIFile& ); - virtual ~AVIFile(); - virtual AVIFile& operator=( const AVIFile& ); - - virtual void Init( int format, int sampleFrequency, int indexType ); - virtual int GetDVFrameInfo( off_t &offset, int &size, int frameNum ); - virtual int GetFrameInfo( off_t &offset, int &size, int frameNum, FOURCC chunkID ); - virtual int GetDVFrame( uint8_t *data, int frameNum ); - virtual int getFrame( void *data, int frameNum, FOURCC chunkID ); - virtual int GetTotalFrames() const; - virtual void PrintDirectoryEntryData( const RIFFDirEntry &entry ) const; - //virtual bool WriteFrame( const Frame &frame ) { return false; } - virtual void ParseList( int parent ); - virtual void ParseRIFF( void ); - virtual void ReadIndex( void ); - virtual void WriteRIFF( void ) - { } - virtual void FlushIndx( int stream ); - virtual void UpdateIndx( int stream, int chunk, int duration ); - virtual void UpdateIdx1( int chunk, int flags ); - virtual bool verifyStreamFormat( FOURCC type ); - virtual bool verifyStream( FOURCC type ); - virtual bool isOpenDML( void ); - virtual void setDVINFO( DVINFO& ) - { } - virtual void setFccHandler( FOURCC type, FOURCC handler ); - virtual bool getStreamFormat( void* data, FOURCC type ); - -protected: - MainAVIHeader mainHdr; - AVISimpleIndex *idx1; - int file_list; - int riff_list; - int hdrl_list; - int avih_chunk; - int movi_list; - int junk_chunk; - int idx1_chunk; - - AVIStreamHeader streamHdr[ 2 ]; - AVISuperIndex *indx[ 2 ]; - AVIStdIndex *ix[ 2 ]; - int indx_chunk[ 2 ]; - int ix_chunk[ 2 ]; - int strl_list[ 2 ]; - int strh_chunk[ 2 ]; - int strf_chunk[ 2 ]; - - int index_type; - int current_ix00; - - DWORD dmlh[ 62 ]; - int odml_list; - int dmlh_chunk; - bool isUpdateIdx1; - -}; - - -/** writing Type 1 DV AVIs - -*/ - -class AVI1File : public AVIFile -{ -public: - AVI1File(); - virtual ~AVI1File(); - - virtual void Init( int format, int sampleFrequency, int indexType ); - //virtual bool WriteFrame( const Frame &frame ); - virtual void WriteRIFF( void ); - virtual void setDVINFO( DVINFO& ); - -private: - DVINFO dvinfo; - - AVI1File( const AVI1File& ); - AVI1File& operator=( const AVI1File& ); -}; - - -/** writing Type 2 (separate audio data) DV AVIs - -This file type contains both audio and video tracks. It is therefore more compatible -to certain Windows programs, which expect any AVI having both audio and video tracks. -The video tracks contain the raw DV data (as in type 1) and the extracted audio tracks. - -Note that because the DV data contains audio information anyway, this means duplication -of data and a slight increase of file size. - -*/ - -class AVI2File : public AVIFile -{ -public: - AVI2File(); - virtual ~AVI2File(); - - virtual void Init( int format, int sampleFrequency, int indexType ); - //virtual bool WriteFrame( const Frame &frame ); - virtual void WriteRIFF( void ); - virtual void setDVINFO( DVINFO& ); - -private: - BITMAPINFOHEADER bitmapinfo; - WAVEFORMATEX waveformatex; - - AVI2File( const AVI2File& ); - AVI2File& operator=( const AVI2File& ); -}; -#endif diff --git a/src/modules/kino/configure b/src/modules/kino/configure deleted file mode 100755 index 5949890c1..000000000 --- a/src/modules/kino/configure +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh - -if [ "$help" != "1" ] -then - - if [ "$targetos" = "Darwin" ] || [ "$targetos" = "MinGW" ] - then - echo "- does not build on OS X or Windows: disabling" - touch ../disable-kino - exit 0 - fi - - # Entirely optional... - pkg-config libquicktime 2> /dev/null - lqt_disabled=$? - - pkg-config libdv 2> /dev/null - libdv_disabled=$? - - echo > config.mak - - if [ "$lqt_disabled" = "0" ] - then - echo "CFLAGS += -DHAVE_LIBQUICKTIME" >> config.mak - echo "HAVE_LIBQUICKTIME=1" >> config.mak - else - echo "- libquicktime not found: only enabling dv avi support" - fi - - if [ "$libdv_disabled" = "0" ] - then - echo "CFLAGS += -DHAVE_LIBDV" >> config.mak - echo "HAVE_LIBDV=1" >> config.mak - fi - - [ "$libdv_disabled" != "0" -a "$lqt_disabled" = "0" ] && echo "- libdv not found: mov dv may not have audio" - - exit 0 -fi diff --git a/src/modules/kino/deprecated b/src/modules/kino/deprecated deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/modules/kino/endian_types.h b/src/modules/kino/endian_types.h deleted file mode 100644 index cd2410ada..000000000 --- a/src/modules/kino/endian_types.h +++ /dev/null @@ -1,280 +0,0 @@ -/* - * - * Quick hack to handle endianness and word length issues. - * Defines _le, _be, and _ne variants to standard ISO types - * like int32_t, that are stored in little-endian, big-endian, - * and native-endian byteorder in memory, respectively. - * Caveat: int32_le_t and friends cannot be used in vararg - * functions like printf() without an explicit cast. - * - * Copyright (c) 2003-2005 Daniel Kobras - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _ENDIAN_TYPES_H -#define _ENDIAN_TYPES_H - -#include - -/* Needed for BYTE_ORDER and BIG/LITTLE_ENDIAN macros. */ -#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) -#ifndef _BSD_SOURCE -# define _BSD_SOURCE -# include -# undef _BSD_SOURCE -#else -# include -#endif -#else -# include -#endif /* !defined(__FreeBSD__) && !defined(__NetBSD__) */ - -#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) -#include -#elif defined(__OpenBSD__) -#define bswap_16(x) swap16(x) -#define bswap_32(x) swap32(x) -#define bswap_64(x) swap64(x) -#else -#define bswap_16(x) bswap16(x) -#define bswap_32(x) bswap32(x) -#define bswap_64(x) bswap64(x) -#endif /* !defined(__FreeBSD__) && !defined(__NetBSD__) */ - -static inline int8_t bswap(const int8_t& x) -{ - return x; -} - -static inline u_int8_t bswap(const u_int8_t& x) -{ - return x; -} - -static inline int16_t bswap(const int16_t& x) -{ - return bswap_16(x); -} - -static inline u_int16_t bswap(const u_int16_t& x) -{ - return bswap_16(x); -} - -static inline int32_t bswap(const int32_t& x) -{ - return bswap_32(x); -} - -static inline u_int32_t bswap(const u_int32_t& x) -{ - return bswap_32(x); -} - -static inline int64_t bswap(const int64_t& x) -{ - return bswap_64(x); -} - -static inline u_int64_t bswap(const u_int64_t& x) -{ - return bswap_64(x); -} - -#define le_to_cpu cpu_to_le -#define be_to_cpu cpu_to_be - -template static inline T cpu_to_le(const T& x) -{ -#if BYTE_ORDER == LITTLE_ENDIAN - return x; -#else - return bswap(x); -#endif -} - -template static inline T cpu_to_be(const T& x) -{ -#if BYTE_ORDER == LITTLE_ENDIAN - return bswap(x); -#else - return x; -#endif -} - -template class le_t { - T m; - T read() const { - return le_to_cpu(m); - }; - void write(const T& n) { - m = cpu_to_le(n); - }; -public: - le_t(void) { - m = 0; - }; - le_t(const T& o) { - write(o); - }; - operator T() const { - return read(); - }; - le_t operator++() { - write(read() + 1); - return *this; - }; - le_t operator++(int) { - write(read() + 1); - return *this; - }; - le_t operator--() { - write(read() - 1); - return *this; - }; - le_t operator--(int) { - write(read() - 1); - return *this; - }; - le_t& operator+=(const T& t) { - write(read() + t); - return *this; - }; - le_t& operator-=(const T& t) { - write(read() - t); - return *this; - }; - le_t& operator&=(const le_t& t) { - m &= t.m; - return *this; - }; - le_t& operator|=(const le_t& t) { - m |= t.m; - return *this; - }; -} __attribute__((packed)); - -/* Just copy-and-pasted from le_t. Too lazy to do it right. */ - -template class be_t { - T m; - T read() const { - return be_to_cpu(m); - }; - void write(const T& n) { - m = cpu_to_be(n); - }; -public: - be_t(void) { - m = 0; - }; - be_t(const T& o) { - write(o); - }; - operator T() const { - return read(); - }; - be_t operator++() { - write(read() + 1); - return *this; - }; - be_t operator++(int) { - write(read() + 1); - return *this; - }; - be_t operator--() { - write(read() - 1); - return *this; - }; - be_t operator--(int) { - write(read() - 1); - return *this; - }; - be_t& operator+=(const T& t) { - write(read() + t); - return *this; - }; - be_t& operator-=(const T& t) { - write(read() - t); - return *this; - }; - be_t& operator&=(const be_t& t) { - m &= t.m; - return *this; - }; - be_t& operator|=(const be_t& t) { - m |= t.m; - return *this; - }; -} __attribute__((packed)); - -/* Define types of native endianness similar to the little and big endian - * versions below. Not really necessary but useful occasionally to emphasize - * endianness of data. - */ - -typedef int8_t int8_ne_t; -typedef int16_t int16_ne_t; -typedef int32_t int32_ne_t; -typedef int64_t int64_ne_t; -typedef u_int8_t u_int8_ne_t; -typedef u_int16_t u_int16_ne_t; -typedef u_int32_t u_int32_ne_t; -typedef u_int64_t u_int64_ne_t; - - -/* The classes work on their native endianness as well, but obviously - * introduce some overhead. Use the faster typedefs to native types - * therefore, unless you're debugging. - */ - -#if BYTE_ORDER == LITTLE_ENDIAN -typedef int8_ne_t int8_le_t; -typedef int16_ne_t int16_le_t; -typedef int32_ne_t int32_le_t; -typedef int64_ne_t int64_le_t; -typedef u_int8_ne_t u_int8_le_t; -typedef u_int16_ne_t u_int16_le_t; -typedef u_int32_ne_t u_int32_le_t; -typedef u_int64_ne_t u_int64_le_t; -typedef int8_t int8_be_t; -typedef be_t int16_be_t; -typedef be_t int32_be_t; -typedef be_t int64_be_t; -typedef u_int8_t u_int8_be_t; -typedef be_t u_int16_be_t; -typedef be_t u_int32_be_t; -typedef be_t u_int64_be_t; -#else -typedef int8_ne_t int8_be_t; -typedef int16_ne_t int16_be_t; -typedef int32_ne_t int32_be_t; -typedef int64_ne_t int64_be_t; -typedef u_int8_ne_t u_int8_be_t; -typedef u_int16_ne_t u_int16_be_t; -typedef u_int32_ne_t u_int32_be_t; -typedef u_int64_ne_t u_int64_be_t; -typedef int8_t int8_le_t; -typedef le_t int16_le_t; -typedef le_t int32_le_t; -typedef le_t int64_le_t; -typedef u_int8_t u_int8_le_t; -typedef le_t u_int16_le_t; -typedef le_t u_int32_le_t; -typedef le_t u_int64_le_t; -#endif - -#endif diff --git a/src/modules/kino/error.cc b/src/modules/kino/error.cc deleted file mode 100644 index 92b93613d..000000000 --- a/src/modules/kino/error.cc +++ /dev/null @@ -1,103 +0,0 @@ -/* -* error.cc Error handling -* Copyright (C) 2000 Arne Schirmacher -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -// C++ includes - -#include -#include -#include -#include - -using std::ostringstream; -using std::string; -using std::endl; -using std::ends; -using std::cerr; - -// C includes - -#include -#include - -// local includes - -#include "error.h" - -void real_fail_neg( int eval, const char *eval_str, const char *func, const char *file, int line ) -{ - if ( eval < 0 ) - { - string exc; - ostringstream sb; - - sb << file << ":" << line << ": In function \"" << func << "\": \"" << eval_str << "\" evaluated to " << eval; - if ( errno != 0 ) - sb << endl << file << ":" << line << ": errno: " << errno << " (" << strerror( errno ) << ")"; - sb << ends; - exc = sb.str(); - cerr << exc << endl; - throw exc; - } -} - - -/** error handler for NULL result codes - - Whenever this is called with a NULL argument, it will throw an - exception. Typically used with functions like malloc() and new(). - -*/ - -void real_fail_null( const void *eval, const char *eval_str, const char *func, const char *file, int line ) -{ - if ( eval == NULL ) - { - - string exc; - ostringstream sb; - - sb << file << ":" << line << ": In function \"" << func << "\": " << eval_str << " is NULL" << ends; - exc = sb.str(); - cerr << exc << endl; - throw exc; - } -} - - -void real_fail_if( bool eval, const char *eval_str, const char *func, const char *file, int line ) -{ - if ( eval == true ) - { - - string exc; - ostringstream sb; - - sb << file << ":" << line << ": In function \"" << func << "\": condition \"" << eval_str << "\" is true"; - if ( errno != 0 ) - sb << endl << file << ":" << line << ": errno: " << errno << " (" << strerror( errno ) << ")"; - sb << ends; - exc = sb.str(); - cerr << exc << endl; - throw exc; - } -} diff --git a/src/modules/kino/error.h b/src/modules/kino/error.h deleted file mode 100644 index 30dedb958..000000000 --- a/src/modules/kino/error.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -* error.h Error handling -* Copyright (C) 2000 Arne Schirmacher -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef _ERROR_H -#define _ERROR_H 1 - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* - * Should check for gcc/g++ and version > 2.6 I suppose - */ -#ifndef __ASSERT_FUNCTION -# define __ASSERT_FUNCTION __PRETTY_FUNCTION__ -#endif - -#define fail_neg(eval) real_fail_neg (eval, #eval, __ASSERT_FUNCTION, __FILE__, __LINE__) -#define fail_null(eval) real_fail_null (eval, #eval, __ASSERT_FUNCTION, __FILE__, __LINE__) -#define fail_if(eval) real_fail_if (eval, #eval, __ASSERT_FUNCTION, __FILE__, __LINE__) - - void real_fail_neg ( int eval, const char * eval_str, const char * func, const char * file, int line ); - void real_fail_null ( const void * eval, const char * eval_str, const char * func, const char * file, int line ); - void real_fail_if ( bool eval, const char * eval_str, const char * func, const char * file, int line ); - - extern void sigpipe_clear( ); - extern int sigpipe_get( ); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/src/modules/kino/factory.c b/src/modules/kino/factory.c deleted file mode 100644 index 46cde7cc9..000000000 --- a/src/modules/kino/factory.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * factory.c -- the factory method interfaces - * Copyright (C) 2005-2014 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include - -extern mlt_producer producer_kino_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); - -MLT_REPOSITORY -{ - MLT_REGISTER( producer_type, "kino", producer_kino_init ); -} diff --git a/src/modules/kino/filehandler.cc b/src/modules/kino/filehandler.cc deleted file mode 100644 index 864087ffd..000000000 --- a/src/modules/kino/filehandler.cc +++ /dev/null @@ -1,941 +0,0 @@ -/* -* filehandler.cc -- saving DV data into different file formats -* Copyright (C) 2000 Arne Schirmacher -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -extern "C" { -#include -} - -#include -#include -#include -#include - -using std::cerr; -using std::endl; -using std::ostringstream; -using std::setw; -using std::setfill; - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// libdv header files -#ifdef HAVE_LIBDV -#include -#endif - -#include "filehandler.h" -#include "error.h" -#include "riff.h" -#include "avi.h" - -FileTracker *FileTracker::instance = NULL; - -FileTracker::FileTracker( ) : mode( CAPTURE_MOVIE_APPEND ) -{ - cerr << ">> Constructing File Capture tracker" << endl; -} - -FileTracker::~FileTracker( ) -{ - cerr << ">> Destroying File Capture tracker" << endl; -} - -FileTracker &FileTracker::GetInstance( ) -{ - if ( instance == NULL ) - instance = new FileTracker(); - - return *instance; -} - -void FileTracker::SetMode( FileCaptureMode mode ) -{ - this->mode = mode; -} - -FileCaptureMode FileTracker::GetMode( ) -{ - return this->mode; -} - -char *FileTracker::Get( int index ) -{ - return list[ index ]; -} - -void FileTracker::Add( const char *file ) -{ - if ( this->mode != CAPTURE_IGNORE ) - { - cerr << ">>>> Registering " << file << " with the tracker" << endl; - list.push_back( strdup( file ) ); - } -} - -unsigned int FileTracker::Size( ) -{ - return list.size(); -} - -void FileTracker::Clear( ) -{ - while ( Size() > 0 ) - { - free( list[ Size() - 1 ] ); - list.pop_back( ); - } - this->mode = CAPTURE_MOVIE_APPEND; -} - -FileHandler::FileHandler() : done( false ), autoSplit( false ), maxFrameCount( 999999 ), - framesWritten( 0 ), filename( "" ) -{ - /* empty body */ - timeStamp = 0; - everyNthFrame = 0; - framesToSkip = 0; - maxFileSize = 0; -} - - -FileHandler::~FileHandler() -{ - /* empty body */ -} - - -bool FileHandler::GetAutoSplit() const -{ - return autoSplit; -} - - -bool FileHandler::GetTimeStamp() const -{ - return timeStamp; -} - - -string FileHandler::GetBaseName() const -{ - return base; -} - - -string FileHandler::GetExtension() const -{ - return extension; -} - - -int FileHandler::GetMaxFrameCount() const -{ - return maxFrameCount; -} - -off_t FileHandler::GetMaxFileSize() const -{ - return maxFileSize; -} - -string FileHandler::GetFilename() const -{ - return filename; -} - - -void FileHandler::SetAutoSplit( bool flag ) -{ - autoSplit = flag; -} - - -void FileHandler::SetTimeStamp( bool flag ) -{ - timeStamp = flag; -} - - -void FileHandler::SetBaseName( const string& s ) -{ - base = s; -} - - -void FileHandler::SetMaxFrameCount( int count ) -{ - assert( count >= 0 ); - maxFrameCount = count; -} - - -void FileHandler::SetEveryNthFrame( int every ) -{ - assert ( every > 0 ); - - everyNthFrame = every; -} - - -void FileHandler::SetMaxFileSize( off_t size ) -{ - assert ( size >= 0 ); - maxFileSize = size; -} - - -#if 0 -void FileHandler::SetSampleFrame( const Frame& sample ) -{ - /* empty body */ -} -#endif - -bool FileHandler::Done() -{ - return done; -} - -#if 0 -bool FileHandler::WriteFrame( const Frame& frame ) -{ - static TimeCode prevTimeCode; - TimeCode timeCode; - - /* If the user wants autosplit, start a new file if a - new recording is detected. */ - prevTimeCode.sec = -1; - frame.GetTimeCode( timeCode ); - int time_diff = timeCode.sec - prevTimeCode.sec; - bool discontinuity = prevTimeCode.sec != -1 && ( time_diff > 1 || ( time_diff < 0 && time_diff > -59 ) ); - if ( FileIsOpen() && GetAutoSplit() == true && ( frame.IsNewRecording() || discontinuity ) ) - { - Close(); - } - - if ( FileIsOpen() == false ) - { - - string filename; - static int counter = 0; - - if ( GetTimeStamp() == true ) - { - ostringstream sb, sb2; - struct tm date; - string recDate; - - if ( ! frame.GetRecordingDate( date ) ) - { - struct timeval tv; - struct timezone tz; - gettimeofday( &tv, &tz ); - localtime_r( static_cast< const time_t * >( &tv.tv_sec ), &date ); - } - sb << setfill( '0' ) - << setw( 4 ) << date.tm_year + 1900 << '.' - << setw( 2 ) << date.tm_mon + 1 << '.' - << setw( 2 ) << date.tm_mday << '_' - << setw( 2 ) << date.tm_hour << '-' - << setw( 2 ) << date.tm_min << '-' - << setw( 2 ) << date.tm_sec; - recDate = sb.str(); - sb2 << GetBaseName() << recDate << GetExtension(); - filename = sb2.str(); - cerr << ">>> Trying " << filename << endl; - } - else - { - struct stat stats; - do - { - ostringstream sb; - sb << GetBaseName() << setfill( '0' ) << setw( 3 ) << ++ counter << GetExtension(); - filename = sb.str(); - cerr << ">>> Trying " << filename << endl; - } - while ( stat( filename.c_str(), &stats ) == 0 ); - } - - SetSampleFrame( frame ); - if ( Create( filename ) == false ) - { - cerr << ">>> Error creating file!" << endl; - return false; - } - framesWritten = 0; - framesToSkip = 0; - } - - /* write frame */ - - if ( framesToSkip == 0 ) - { - if ( 0 > Write( frame ) ) - { - cerr << ">>> Error writing frame!" << endl; - return false; - } - framesToSkip = everyNthFrame; - ++framesWritten; - } - framesToSkip--; - - /* If the frame count is exceeded, close the current file. - If the autosplit flag is set, a new file will be created in the next iteration. - If the flag is not set, we are done. */ - - if ( ( GetMaxFrameCount() > 0 ) && - ( framesWritten >= GetMaxFrameCount() ) ) - { - Close(); - done = !GetAutoSplit(); - } - - /* If the file size could be exceeded by another frame, close the current file. - If the autosplit flag is set, a new file will be created on the next iteration. - If the flag is not set, we are done. */ - /* not exact, but should be good enough to prevent going over. */ - if ( FileIsOpen() ) - { - AudioInfo info; - frame.GetAudioInfo( info ); - if ( ( GetFileSize() > 0 ) && ( GetMaxFileSize() > 0 ) && - ( GetFileSize() + frame.GetFrameSize() + info.samples * 4 + 12 ) - >= GetMaxFileSize() ) - { // 12 = sizeof chunk metadata - Close(); - done = !GetAutoSplit(); - } - } - prevTimeCode.sec = timeCode.sec; - return true; -} -#endif - -RawHandler::RawHandler() : fd( -1 ) -{ - extension = ".dv"; - numBlocks = 0; -} - - -RawHandler::~RawHandler() -{ - Close(); -} - - -bool RawHandler::FileIsOpen() -{ - return fd != -1; -} - - -bool RawHandler::Create( const string& filename ) -{ - fd = open( filename.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_NONBLOCK, 0644 ); - if ( fd != -1 ) - { - FileTracker::GetInstance().Add( filename.c_str() ); - this->filename = filename; - } - return ( fd != -1 ); -} - - -#if 0 -int RawHandler::Write( const Frame& frame ) -{ - int result = write( fd, frame.data, frame.GetFrameSize() ); - return result; -} -#endif - -int RawHandler::Close() -{ - if ( fd != -1 ) - { - close( fd ); - fd = -1; - } - return 0; -} - - -off_t RawHandler::GetFileSize() -{ - struct stat file_status; - fstat( fd, &file_status ); - return file_status.st_size; -} - -int RawHandler::GetTotalFrames() -{ - return GetFileSize() / ( 480 * numBlocks ); -} - - -bool RawHandler::Open( const char *s ) -{ - unsigned char data[ 4 ]; - assert( fd == -1 ); - fd = open( s, O_RDONLY | O_NONBLOCK ); - if ( fd < 0 ) - return false; - if ( read( fd, data, 4 ) < 0 ) - return false; - if ( lseek( fd, 0, SEEK_SET ) < 0 ) - return false; - numBlocks = ( ( data[ 3 ] & 0x80 ) == 0 ) ? 250 : 300; - filename = s; - return true; - -} - -int RawHandler::GetFrame( uint8_t *data, int frameNum ) -{ - assert( fd != -1 ); - int size = 480 * numBlocks; - if ( frameNum < 0 ) - return -1; - off_t offset = ( ( off_t ) frameNum * ( off_t ) size ); - fail_if( lseek( fd, offset, SEEK_SET ) == ( off_t ) - 1 ); - if ( read( fd, data, size ) > 0 ) - return 0; - else - return -1; -} - - -/***************************************************************************/ - - -AVIHandler::AVIHandler( int format ) : avi( NULL ), aviFormat( format ), isOpenDML( false ), - fccHandler( make_fourcc( "dvsd" ) ), channels( 2 ), isFullyInitialized( false ), - audioBuffer( NULL ) -{ - extension = ".avi"; - for ( int c = 0; c < 4; c++ ) - audioChannels[ c ] = NULL; - memset( &dvinfo, 0, sizeof( dvinfo ) ); -} - - -AVIHandler::~AVIHandler() -{ - delete audioBuffer; - audioBuffer = NULL; - - for ( int c = 0; c < 4; c++ ) - { - delete audioChannels[ c ]; - audioChannels[ c ] = NULL; - } - - delete avi; -} - -#if 0 -void AVIHandler::SetSampleFrame( const Frame& sample ) -{ - Pack pack; - sample.GetAudioInfo( audioInfo ); - sample.GetVideoInfo( videoInfo ); - - sample.GetAAUXPack( 0x50, pack ); - dvinfo.dwDVAAuxSrc = *( DWORD* ) ( pack.data + 1 ); - sample.GetAAUXPack( 0x51, pack ); - dvinfo.dwDVAAuxCtl = *( DWORD* ) ( pack.data + 1 ); - - sample.GetAAUXPack( 0x52, pack ); - dvinfo.dwDVAAuxSrc1 = *( DWORD* ) ( pack.data + 1 ); - sample.GetAAUXPack( 0x53, pack ); - dvinfo.dwDVAAuxCtl1 = *( DWORD* ) ( pack.data + 1 ); - - sample.GetVAUXPack( 0x60, pack ); - dvinfo.dwDVVAuxSrc = *( DWORD* ) ( pack.data + 1 ); - sample.GetVAUXPack( 0x61, pack ); - dvinfo.dwDVVAuxCtl = *( DWORD* ) ( pack.data + 1 ); - -#ifdef WITH_LIBDV - - if ( sample.decoder->std == e_dv_std_smpte_314m ) - fccHandler = make_fourcc( "dv25" ); -#endif -} -#endif - -bool AVIHandler::FileIsOpen() -{ - return avi != NULL; -} - - -bool AVIHandler::Create( const string& filename ) -{ - assert( avi == NULL ); - - switch ( aviFormat ) - { - - case AVI_DV1_FORMAT: - fail_null( avi = new AVI1File ); - if ( !avi || avi->Create( filename.c_str() ) == false ) - return false; - //avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency, AVI_LARGE_INDEX ); - break; - - case AVI_DV2_FORMAT: - fail_null( avi = new AVI2File ); - if ( !avi || avi->Create( filename.c_str() ) == false ) - return false; - //if ( GetOpenDML() ) - //avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency, - //( AVI_SMALL_INDEX | AVI_LARGE_INDEX ) ); - //else - //avi->Init( videoInfo.isPAL ? AVI_PAL : AVI_NTSC, audioInfo.frequency, - //( AVI_SMALL_INDEX ) ); - break; - - default: - assert( aviFormat == AVI_DV1_FORMAT || aviFormat == AVI_DV2_FORMAT ); - } - - avi->setDVINFO( dvinfo ); - avi->setFccHandler( make_fourcc( "iavs" ), fccHandler ); - avi->setFccHandler( make_fourcc( "vids" ), fccHandler ); - this->filename = filename; - FileTracker::GetInstance().Add( filename.c_str() ); - return ( avi != NULL ); -} - -#if 0 -int AVIHandler::Write( const Frame& frame ) -{ - assert( avi != NULL ); - try - { - return avi->WriteFrame( frame ) ? 0 : -1; - } - catch (...) - { - return -1; - } -} -#endif - -int AVIHandler::Close() -{ - if ( avi != NULL ) - { - avi->WriteRIFF(); - delete avi; - avi = NULL; - } - if ( audioBuffer != NULL ) - { - delete audioBuffer; - audioBuffer = NULL; - } - for ( int c = 0; c < 4; c++ ) - { - if ( audioChannels[ c ] != NULL ) - { - delete audioChannels[ c ]; - audioChannels[ c ] = NULL; - } - } - isFullyInitialized = false; - return 0; -} - -off_t AVIHandler::GetFileSize() -{ - return avi->GetFileSize(); -} - -int AVIHandler::GetTotalFrames() -{ - return avi->GetTotalFrames(); -} - - -bool AVIHandler::Open( const char *s ) -{ - assert( avi == NULL ); - fail_null( avi = new AVI1File ); - if ( avi->Open( s ) ) - { - avi->ParseRIFF(); - if ( ! ( - avi->verifyStreamFormat( make_fourcc( "dvsd" ) ) || - avi->verifyStreamFormat( make_fourcc( "DVSD" ) ) || - avi->verifyStreamFormat( make_fourcc( "dvcs" ) ) || - avi->verifyStreamFormat( make_fourcc( "DVCS" ) ) || - avi->verifyStreamFormat( make_fourcc( "dvcp" ) ) || - avi->verifyStreamFormat( make_fourcc( "DVCP" ) ) || - avi->verifyStreamFormat( make_fourcc( "CDVC" ) ) || - avi->verifyStreamFormat( make_fourcc( "cdvc" ) ) || - avi->verifyStreamFormat( make_fourcc( "DV25" ) ) || - avi->verifyStreamFormat( make_fourcc( "dv25" ) ) ) ) - return false; - avi->ReadIndex(); - if ( avi->verifyStream( make_fourcc( "auds" ) ) ) - aviFormat = AVI_DV2_FORMAT; - else - aviFormat = AVI_DV1_FORMAT; - isOpenDML = avi->isOpenDML(); - filename = s; - return true; - } - else - return false; - -} - -int AVIHandler::GetFrame( uint8_t *data, int frameNum ) -{ - int result = avi->GetDVFrame( data, frameNum ); -#if 0 - if ( result == 0 ) - { - /* get the audio from the audio stream, if available */ - if ( aviFormat == AVI_DV2_FORMAT ) - { - WAVEFORMATEX wav; - - if ( ! isFullyInitialized && - avi->getStreamFormat( ( void* ) &wav, make_fourcc( "auds" ) ) ) - { - if ( channels > 0 && channels < 5 ) - { - // Allocate interleaved audio buffer - audioBuffer = new int16_t[ 2 * DV_AUDIO_MAX_SAMPLES * channels ]; - - // Allocate non-interleaved audio buffers - for ( int c = 0; c < channels; c++ ) - audioChannels[ c ] = new int16_t[ 2 * DV_AUDIO_MAX_SAMPLES ]; - - // Get the audio parameters from AVI for subsequent calls to method - audioInfo.channels = wav.nChannels; - audioInfo.frequency = wav.nSamplesPerSec; - - // Skip initialization on subsequent calls to method - isFullyInitialized = true; - cerr << ">>> using audio from separate AVI audio stream" << endl; - } - } - - // Get the frame from AVI - int n = avi->getFrame( audioBuffer, frameNum, make_fourcc( "01wb" ) ); - if ( n > 0 ) - { - // Temporary pointer to audio scratch buffer - int16_t * s = audioBuffer; - - // Determine samples in this frame - audioInfo.samples = n / audioInfo.channels / sizeof( int16_t ); - - // Convert interleaved audio into non-interleaved - for ( int n = 0; n < audioInfo.samples; ++n ) - for ( int i = 0; i < audioInfo.channels; i++ ) - audioChannels[ i ][ n ] = *s++; - - // Write interleaved audio into frame - frame.EncodeAudio( audioInfo, audioChannels ); - } - } - - // Parse important metadata in DV bitstream - frame.ExtractHeader(); - } -#endif - return result; -} - - -void AVIHandler::SetOpenDML( bool flag ) -{ - isOpenDML = flag; -} - - -bool AVIHandler::GetOpenDML() const -{ - return isOpenDML; -} - - -/***************************************************************************/ - -#ifdef HAVE_LIBQUICKTIME - -#ifndef HAVE_LIBDV -#define DV_AUDIO_MAX_SAMPLES 1944 -#endif - -// Missing fourcc's in libquicktime (allows compilation) -#ifndef QUICKTIME_DV_AVID -#define QUICKTIME_DV_AVID "AVdv" -#endif - -#ifndef QUICKTIME_DV_AVID_A -#define QUICKTIME_DV_AVID_A "dvcp" -#endif - -#ifndef QUICKTIME_DVCPRO -#define QUICKTIME_DVCPRO "dvpp" -#endif - -QtHandler::QtHandler() : fd( NULL ) -{ - extension = ".mov"; - Init(); -} - - -QtHandler::~QtHandler() -{ - Close(); -} - -void QtHandler::Init() -{ - if ( fd != NULL ) - Close(); - - fd = NULL; - samplingRate = 0; - samplesPerBuffer = 0; - channels = 2; - audioBuffer = NULL; - audioChannelBuffer = NULL; - isFullyInitialized = false; -} - - -bool QtHandler::FileIsOpen() -{ - return fd != NULL; -} - - -bool QtHandler::Create( const string& filename ) -{ - Init(); - - if ( open( filename.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_NONBLOCK, 0644 ) != -1 ) - { - fd = quicktime_open( const_cast( filename.c_str() ), 0, 1 ); - if ( fd != NULL ) - FileTracker::GetInstance().Add( filename.c_str() ); - } - else - return false; - this->filename = filename; - return true; -} - -void QtHandler::AllocateAudioBuffers() -{ - if ( channels > 0 && channels < 5 ) - { - audioBufferSize = DV_AUDIO_MAX_SAMPLES * 2; - audioBuffer = new int16_t[ audioBufferSize * channels ]; - - audioChannelBuffer = new short int * [ channels ]; - for ( int c = 0; c < channels; c++ ) - audioChannelBuffer[ c ] = new short int[ audioBufferSize ]; - isFullyInitialized = true; - } -} - -inline void QtHandler::DeinterlaceStereo16( void* pInput, int iBytes, - void* pLOutput, void* pROutput ) -{ - short int * piSampleInput = ( short int* ) pInput; - short int* piSampleLOutput = ( short int* ) pLOutput; - short int* piSampleROutput = ( short int* ) pROutput; - - while ( ( char* ) piSampleInput < ( ( char* ) pInput + iBytes ) ) - { - *piSampleLOutput++ = *piSampleInput++; - *piSampleROutput++ = *piSampleInput++; - } -} - -#if 0 -int QtHandler::Write( const Frame& frame ) -{ - if ( ! isFullyInitialized ) - { - AudioInfo audio; - - if ( frame.GetAudioInfo( audio ) ) - { - channels = 2; - quicktime_set_audio( fd, channels, audio.frequency, 16, QUICKTIME_TWOS ); - } - else - { - channels = 0; - } - - quicktime_set_video( fd, 1, 720, frame.IsPAL() ? 576 : 480, - frame.GetFrameRate(), QUICKTIME_DV ); - AllocateAudioBuffers(); - } - - int result = quicktime_write_frame( fd, const_cast( frame.data ), - frame.GetFrameSize(), 0 ); - - if ( channels > 0 ) - { - AudioInfo audio; - if ( frame.GetAudioInfo( audio ) && ( unsigned int ) audio.samples < audioBufferSize ) - { - long bytesRead = frame.ExtractAudio( audioBuffer ); - - DeinterlaceStereo16( audioBuffer, bytesRead, - audioChannelBuffer[ 0 ], - audioChannelBuffer[ 1 ] ); - - quicktime_encode_audio( fd, audioChannelBuffer, NULL, audio.samples ); - } - } - return result; -} -#endif - -int QtHandler::Close() -{ - if ( fd != NULL ) - { - quicktime_close( fd ); - fd = NULL; - } - if ( audioBuffer != NULL ) - { - delete audioBuffer; - audioBuffer = NULL; - } - if ( audioChannelBuffer != NULL ) - { - for ( int c = 0; c < channels; c++ ) - delete audioChannelBuffer[ c ]; - delete audioChannelBuffer; - audioChannelBuffer = NULL; - } - return 0; -} - - -off_t QtHandler::GetFileSize() -{ - struct stat file_status; - stat( filename.c_str(), &file_status ); - return file_status.st_size; -} - - -int QtHandler::GetTotalFrames() -{ - return ( int ) quicktime_video_length( fd, 0 ); -} - - -bool QtHandler::Open( const char *s ) -{ - Init(); - - fd = quicktime_open( s, 1, 0 ); - if ( fd == NULL ) - { - fprintf( stderr, "Error opening: %s\n", s ); - return false; - } - - if ( quicktime_has_video( fd ) <= 0 ) - { - fprintf( stderr, "There must be at least one video track in the input file (%s).\n", - s ); - Close(); - return false; - } - char * fcc = quicktime_video_compressor( fd, 0 ); - if ( strncmp( fcc, QUICKTIME_DV, 4 ) != 0 && - strncmp( fcc, QUICKTIME_DV_AVID, 4 ) != 0 && - strncmp( fcc, QUICKTIME_DV_AVID_A, 4 ) != 0 && - strncmp( fcc, QUICKTIME_DVCPRO, 4 ) != 0 ) - { - Close(); - return false; - } - if ( quicktime_has_audio( fd ) ) - channels = quicktime_track_channels( fd, 0 ); - filename = s; - return true; -} - -int QtHandler::GetFrame( uint8_t *data, int frameNum ) -{ - assert( fd != NULL ); - - quicktime_set_video_position( fd, frameNum, 0 ); - quicktime_read_frame( fd, data, 0 ); - -#ifdef HAVE_LIBDV - if ( quicktime_has_audio( fd ) ) - { - if ( ! isFullyInitialized ) - AllocateAudioBuffers(); - - // Fetch the frequency of the audio track and calc number of samples needed - int frequency = quicktime_sample_rate( fd, 0 ); - float fps = ( data[ 3 ] & 0x80 ) ? 25.0f : 29.97f; - int samples = mlt_sample_calculator( fps, frequency, frameNum ); - int64_t seek = mlt_sample_calculator_to_now( fps, frequency, frameNum ); - - // Obtain a dv encoder and initialise it with minimal info - dv_encoder_t *encoder = dv_encoder_new( 0, 0, 0 ); - encoder->isPAL = ( data[ 3 ] & 0x80 ); - encoder->samples_this_frame = samples; - - // Seek to the calculated position and decode - quicktime_set_audio_position( fd, seek, 0 ); - lqt_decode_audio( fd, audioChannelBuffer, NULL, (long) samples ); - - // Encode the audio on the frame and done - dv_encode_full_audio( encoder, audioChannelBuffer, channels, frequency, data ); - dv_encoder_free( encoder ); - } -#endif - - return 0; -} -#endif diff --git a/src/modules/kino/filehandler.h b/src/modules/kino/filehandler.h deleted file mode 100644 index fdab94183..000000000 --- a/src/modules/kino/filehandler.h +++ /dev/null @@ -1,217 +0,0 @@ -/* -* filehandler.h -* Copyright (C) 2000 Arne Schirmacher -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef _FILEHANDLER_H -#define _FILEHANDLER_H - -// enum { PAL_FORMAT, NTSC_FORMAT, AVI_DV1_FORMAT, AVI_DV2_FORMAT, QT_FORMAT, RAW_FORMAT, TEST_FORMAT, UNDEFINED }; - -#include -using std::vector; - -#include -using std::string; - -#include "riff.h" -#include "avi.h" -#include -#include - -enum { AVI, PLAYLIST, RAW_DV, QT, UNKNOWN_FORMAT }; -enum { PAL_FORMAT, NTSC_FORMAT, AVI_DV1_FORMAT, AVI_DV2_FORMAT, QT_FORMAT, RAW_FORMAT, TEST_FORMAT, UNDEFINED }; -enum { DISPLAY_XX, DISPLAY_GDKRGB, DISPLAY_GDKRGB32, DISPLAY_XV, DISPLAY_SDL }; - -enum { NORM_UNSPECIFIED=0, NORM_PAL=1, NORM_NTSC=2 }; -enum { AUDIO_32KHZ=0, AUDIO_44KHZ=1, AUDIO_48KHZ=2 }; -enum { ASPECT_43=0, ASPECT_169=1 }; - -enum FileCaptureMode { - CAPTURE_IGNORE, - CAPTURE_FRAME_APPEND, - CAPTURE_FRAME_INSERT, - CAPTURE_MOVIE_APPEND -}; - -class FileTracker -{ -protected: - FileTracker(); - ~FileTracker(); -public: - static FileTracker &GetInstance( ); - void SetMode( FileCaptureMode ); - FileCaptureMode GetMode( ); - unsigned int Size(); - char *Get( int ); - void Add( const char * ); - void Clear( ); -private: - static FileTracker *instance; - vector list; - FileCaptureMode mode; -}; - -class FileHandler -{ -public: - - FileHandler(); - virtual ~FileHandler(); - - virtual bool GetAutoSplit() const; - virtual bool GetTimeStamp() const; - virtual string GetBaseName() const; - virtual string GetExtension() const; - virtual int GetMaxFrameCount() const; - virtual off_t GetMaxFileSize() const; - virtual off_t GetFileSize() = 0; - virtual int GetTotalFrames() = 0; - virtual string GetFilename() const; - - virtual void SetAutoSplit( bool ); - virtual void SetTimeStamp( bool ); - virtual void SetBaseName( const string& base ); - virtual void SetMaxFrameCount( int ); - virtual void SetEveryNthFrame( int ); - virtual void SetMaxFileSize( off_t ); - //virtual void SetSampleFrame( const Frame& sample ); - - //virtual bool WriteFrame( const Frame& frame ); - virtual bool FileIsOpen() = 0; - virtual bool Create( const string& filename ) = 0; - //virtual int Write( const Frame& frame ) = 0; - virtual int Close() = 0; - virtual bool Done( void ); - - virtual bool Open( const char *s ) = 0; - virtual int GetFrame( uint8_t *data, int frameNum ) = 0; - int GetFramesWritten() const - { - return framesWritten; - } - -protected: - bool done; - bool autoSplit; - bool timeStamp; - int maxFrameCount; - int framesWritten; - int everyNthFrame; - int framesToSkip; - off_t maxFileSize; - string base; - string extension; - string filename; -}; - - -class RawHandler: public FileHandler -{ -public: - int fd; - - RawHandler(); - ~RawHandler(); - - bool FileIsOpen(); - bool Create( const string& filename ); - //int Write( const Frame& frame ); - int Close(); - off_t GetFileSize(); - int GetTotalFrames(); - bool Open( const char *s ); - int GetFrame( uint8_t *data, int frameNum ); -private: - int numBlocks; -}; - - -class AVIHandler: public FileHandler -{ -public: - AVIHandler( int format = AVI_DV1_FORMAT ); - ~AVIHandler(); - - //void SetSampleFrame( const Frame& sample ); - bool FileIsOpen(); - bool Create( const string& filename ); - //int Write( const Frame& frame ); - int Close(); - off_t GetFileSize(); - int GetTotalFrames(); - bool Open( const char *s ); - int GetFrame( uint8_t *data, int frameNum ); - bool GetOpenDML() const; - void SetOpenDML( bool ); - int GetFormat() const - { - return aviFormat; - } - -protected: - AVIFile *avi; - int aviFormat; - //AudioInfo audioInfo; - //VideoInfo videoInfo; - bool isOpenDML; - DVINFO dvinfo; - FOURCC fccHandler; - int channels; - bool isFullyInitialized; - int16_t *audioBuffer; - int16_t *audioChannels[ 4 ]; -}; - - -#ifdef HAVE_LIBQUICKTIME -#include - -class QtHandler: public FileHandler -{ -public: - QtHandler(); - ~QtHandler(); - - bool FileIsOpen(); - bool Create( const string& filename ); - //int Write( const Frame& frame ); - int Close(); - off_t GetFileSize(); - int GetTotalFrames(); - bool Open( const char *s ); - int GetFrame( uint8_t *data, int frameNum ); - void AllocateAudioBuffers(); - -private: - quicktime_t *fd; - long samplingRate; - int samplesPerBuffer; - int channels; - bool isFullyInitialized; - unsigned int audioBufferSize; - int16_t *audioBuffer; - short int** audioChannelBuffer; - - void Init(); - inline void DeinterlaceStereo16( void* pInput, int iBytes, void* pLOutput, void* pROutput ); - -}; -#endif - -#endif diff --git a/src/modules/kino/gpl b/src/modules/kino/gpl deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/modules/kino/kino_wrapper.cc b/src/modules/kino/kino_wrapper.cc deleted file mode 100644 index fca7106b5..000000000 --- a/src/modules/kino/kino_wrapper.cc +++ /dev/null @@ -1,108 +0,0 @@ -/* - * kino_wrapper.cc -- c wrapper for kino file handler - * Copyright (C) 2005-2014 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include - -#include "kino_wrapper.h" -#include "filehandler.h" - -extern "C" -{ - -#include - -struct kino_wrapper_s -{ - FileHandler *handler; - int is_pal; -}; - -kino_wrapper kino_wrapper_init( ) -{ - kino_wrapper self = ( kino_wrapper )malloc( sizeof( kino_wrapper_s ) ); - if ( self != NULL ) - self->handler = NULL; - return self; -} - -int kino_wrapper_open( kino_wrapper self, char *src ) -{ - if ( self != NULL ) - { - // Rough file determination based on file type - if ( strncasecmp( strrchr( src, '.' ), ".avi", 4 ) == 0 ) - self->handler = new AVIHandler( ); - else if ( strncasecmp( strrchr( src, '.' ), ".dv", 3 ) == 0 || strncasecmp( strrchr( src, '.' ), ".dif", 4 ) == 0 ) - self->handler = new RawHandler( ); - #ifdef HAVE_LIBQUICKTIME - else if ( strncasecmp( strrchr( src, '.' ), ".mov", 4 ) == 0 ) - self->handler = new QtHandler( ); - #endif - - // Open the file if we have a handler - if ( self->handler != NULL ) - if ( !self->handler->Open( src ) ) - self = NULL; - - // Check the first frame to see if it's PAL or NTSC - if ( self != NULL && self->handler != NULL ) - { - uint8_t *data = ( uint8_t * )mlt_pool_alloc( 144000 ); - if ( self->handler->GetFrame( data, 0 ) == 0 ) - self->is_pal = data[3] & 0x80; - else - self = NULL; - mlt_pool_release( data ); - } - } - - return kino_wrapper_is_open( self ); -} - -int kino_wrapper_get_frame_count( kino_wrapper self ) -{ - return self != NULL && self->handler != NULL ? self->handler->GetTotalFrames( ) : 0; -} - -int kino_wrapper_is_open( kino_wrapper self ) -{ - return self != NULL && self->handler != NULL ? self->handler->FileIsOpen( ) : 0; -} - -int kino_wrapper_is_pal( kino_wrapper self ) -{ - return self != NULL ? self->is_pal : 0; -} - -int kino_wrapper_get_frame( kino_wrapper self, uint8_t *data, int index ) -{ - return self != NULL && self->handler != NULL ? !self->handler->GetFrame( data, index ) : 0; -} - -void kino_wrapper_close( kino_wrapper self ) -{ - if ( self ) - delete self->handler; - free( self ); -} - -} - - diff --git a/src/modules/kino/kino_wrapper.h b/src/modules/kino/kino_wrapper.h deleted file mode 100644 index f96ebddc1..000000000 --- a/src/modules/kino/kino_wrapper.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * kino_wrapper.h -- c wrapper for kino file handler - * Copyright (C) 2005-2014 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef MLT_PRODUCER_KINO_WRAPPER_H_ -#define MLT_PRODUCER_KINO_WRAPPER_H_ - -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef struct kino_wrapper_s *kino_wrapper; - -extern kino_wrapper kino_wrapper_init( ); -extern int kino_wrapper_open( kino_wrapper, char * ); -extern int kino_wrapper_is_open( kino_wrapper ); -extern int kino_wrapper_is_pal( kino_wrapper ); -extern int kino_wrapper_get_frame_count( kino_wrapper ); -extern int kino_wrapper_get_frame( kino_wrapper, uint8_t *, int ); -extern void kino_wrapper_close( kino_wrapper ); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/modules/kino/producer_kino.c b/src/modules/kino/producer_kino.c deleted file mode 100644 index 21696ce71..000000000 --- a/src/modules/kino/producer_kino.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * producer_kino.c -- a DV file format parser - * Copyright (C) 2005-2014 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include "kino_wrapper.h" - -/* NB: This is an abstract producer - it provides no codec support whatsoever. */ - -#define FRAME_SIZE_525_60 10 * 150 * 80 -#define FRAME_SIZE_625_50 12 * 150 * 80 - -typedef struct producer_kino_s *producer_kino; - -struct producer_kino_s -{ - struct mlt_producer_s parent; - kino_wrapper wrapper; -}; - -static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); -static void producer_close( mlt_producer parent ); - -mlt_producer producer_kino_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename ) -{ - kino_wrapper wrapper = kino_wrapper_init( ); - - if ( kino_wrapper_open( wrapper, filename ) ) - { - producer_kino this = calloc( 1, sizeof( struct producer_kino_s ) ); - - if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) - { - mlt_producer producer = &this->parent; - mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); - double fps = kino_wrapper_is_pal( wrapper ) ? 25 : 30000.0 / 1001.0; - - // Assign the wrapper - this->wrapper = wrapper; - - // Pass wrapper properties (frame rate, count etc) - mlt_properties_set_position( properties, "length", kino_wrapper_get_frame_count( wrapper ) ); - mlt_properties_set_position( properties, "in", 0 ); - mlt_properties_set_position( properties, "out", kino_wrapper_get_frame_count( wrapper ) - 1 ); - mlt_properties_set_double( properties, "real_fps", fps ); - mlt_properties_set( properties, "resource", filename ); - - // Register transport implementation with the producer - producer->close = ( mlt_destructor )producer_close; - - // Register our get_frame implementation with the producer - producer->get_frame = producer_get_frame; - - // Return the producer - return producer; - } - free( this ); - } - - kino_wrapper_close( wrapper ); - - return NULL; -} - -static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) -{ - producer_kino this = producer->child; - uint8_t *data = mlt_pool_alloc( FRAME_SIZE_625_50 ); - - // Obtain the current frame number - uint64_t position = mlt_producer_frame( producer ); - - // Create an empty frame - *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); - - // Seek and fetch - if ( kino_wrapper_get_frame( this->wrapper, data, position ) ) - { - // Get the frames properties - mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); - - // Determine if we're PAL or NTSC - int is_pal = kino_wrapper_is_pal( this->wrapper ); - - // Pass the dv data - mlt_properties_set_data( properties, "dv_data", data, FRAME_SIZE_625_50, ( mlt_destructor )mlt_pool_release, NULL ); - - // Update other info on the frame - mlt_properties_set_int( properties, "width", 720 ); - mlt_properties_set_int( properties, "height", is_pal ? 576 : 480 ); - mlt_properties_set_int( properties, "top_field_first", is_pal ? 0 : ( data[ 5 ] & 0x07 ) == 0 ? 0 : 1 ); - } - else - { - mlt_pool_release( data ); - } - - // Update timecode on the frame we're creating - mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); - - // Calculate the next timecode - mlt_producer_prepare_next( producer ); - - return 0; -} - -static void producer_close( mlt_producer parent ) -{ - if ( parent != NULL ) - { - // Obtain this - producer_kino this = parent->child; - - // Close the file - if ( this != NULL ) - kino_wrapper_close( this->wrapper ); - - // Close the parent - parent->close = NULL; - mlt_producer_close( parent ); - - // Free the memory - free( this ); - } -} diff --git a/src/modules/kino/riff.cc b/src/modules/kino/riff.cc deleted file mode 100644 index 162cc51bd..000000000 --- a/src/modules/kino/riff.cc +++ /dev/null @@ -1,659 +0,0 @@ -/* -* riff.cc library for RIFF file format i/o -* Copyright (C) 2000 - 2002 Arne Schirmacher -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -// C++ includes - -#include -//#include -#include -#include - -using std::cout; -using std::hex; -using std::dec; -using std::setw; -using std::setfill; -using std::endl; - -// C includes - -#include -#include -#include - -// local includes - -#include "error.h" -#include "riff.h" - - -/** make a 32 bit "string-id" - - \param s a pointer to 4 chars - \return the 32 bit "string id" - \bugs It is not checked whether we really have 4 characters - - Some compilers understand constants like int id = 'ABCD'; but I - could not get it working on the gcc compiler so I had to use this - workaround. We can now use id = make_fourcc("ABCD") instead. */ - -FOURCC make_fourcc( const char *s ) -{ - if ( s[ 0 ] == 0 ) - return 0; - else - return *( ( FOURCC* ) s ); -} - - -RIFFDirEntry::RIFFDirEntry() -{ - type = 0; - name = 0; - length = 0; - offset = 0; - parent = 0; - written = 0; -} - - -RIFFDirEntry::RIFFDirEntry ( FOURCC t, FOURCC n, int l, int o, int p ) : type( t ), name( n ), length( l ), offset( o ), parent( p ), written( 0 ) -{} - - -/** Creates the object without an output file. - -*/ - -RIFFFile::RIFFFile() : fd( -1 ) -{ - pthread_mutex_init( &file_mutex, NULL ); -} - - -/* Copy constructor - - Duplicate the file descriptor -*/ - -RIFFFile::RIFFFile( const RIFFFile& riff ) : fd( -1 ) -{ - if ( riff.fd != -1 ) - { - fd = dup( riff.fd ); - } - directory = riff.directory; -} - - -/** Destroys the object. - - If it has an associated opened file, close it. */ - -RIFFFile::~RIFFFile() -{ - Close(); - pthread_mutex_destroy( &file_mutex ); -} - - -RIFFFile& RIFFFile::operator=( const RIFFFile& riff ) -{ - if ( fd != riff.fd ) - { - Close(); - if ( riff.fd != -1 ) - { - fd = dup( riff.fd ); - } - directory = riff.directory; - } - return *this; -} - - -/** Creates or truncates the file. - - \param s the filename -*/ - -bool RIFFFile::Create( const char *s ) -{ - fd = open( s, O_RDWR | O_NONBLOCK | O_CREAT | O_TRUNC, 00644 ); - - if ( fd == -1 ) - return false; - else - return true; -} - - -/** Opens the file read only. - - \param s the filename -*/ - -bool RIFFFile::Open( const char *s ) -{ - fd = open( s, O_RDONLY | O_NONBLOCK ); - - if ( fd == -1 ) - return false; - else - return true; -} - - -/** Destroys the object. - - If it has an associated opened file, close it. */ - -void RIFFFile::Close() -{ - if ( fd != -1 ) - { - close( fd ); - fd = -1; - } -} - - -/** Adds an entry to the list of containers. - - \param type the type of this entry - \param name the name - \param length the length of the data in the container - \param list the container in which this object is contained. - \return the ID of the newly created entry - - The topmost object is not contained in any other container. Use - the special ID RIFF_NO_PARENT to create the topmost object. */ - -int RIFFFile::AddDirectoryEntry( FOURCC type, FOURCC name, off_t length, int list ) -{ - /* Put all parameters in an RIFFDirEntry object. The offset is - currently unknown. */ - - RIFFDirEntry entry( type, name, length, 0 /* offset */, list ); - - /* If the new chunk is in a list, then get the offset and size - of that list. The offset of this chunk is the end of the list - (parent_offset + parent_length) plus the size of the chunk - header. */ - - if ( list != RIFF_NO_PARENT ) - { - RIFFDirEntry parent = GetDirectoryEntry( list ); - entry.offset = parent.offset + parent.length + RIFF_HEADERSIZE; - } - - /* The list which this new chunk is a member of has now increased in - size. Get that directory entry and bump up its length by the size - of the chunk. Since that list may also be contained in another - list, walk up to the top of the tree. */ - - while ( list != RIFF_NO_PARENT ) - { - RIFFDirEntry parent = GetDirectoryEntry( list ); - parent.length += RIFF_HEADERSIZE + length; - SetDirectoryEntry( list, parent ); - list = parent.parent; - } - - directory.insert( directory.end(), entry ); - - return directory.size() - 1; -} - - -/** Modifies an entry. - - \param i the ID of the entry which is to modify - \param type the type of this entry - \param name the name - \param length the length of the data in the container - \param list the container in which this object is contained. - \note Do not change length, offset, or the parent container. - \note Do not change an empty name ("") to a name and vice versa */ - -void RIFFFile::SetDirectoryEntry( int i, FOURCC type, FOURCC name, off_t length, off_t offset, int list ) -{ - RIFFDirEntry entry( type, name, length, offset, list ); - - assert( i >= 0 && i < ( int ) directory.size() ); - - directory[ i ] = entry; -} - - -/** Modifies an entry. - - The entry.written flag is set to false because the contents has been modified - - \param i the ID of the entry which is to modify - \param entry the new entry - \note Do not change length, offset, or the parent container. - \note Do not change an empty name ("") to a name and vice versa */ - -void RIFFFile::SetDirectoryEntry( int i, RIFFDirEntry &entry ) -{ - assert( i >= 0 && i < ( int ) directory.size() ); - - entry.written = false; - directory[ i ] = entry; -} - - -/** Retrieves an entry. - - Gets the most important member variables. - - \param i the ID of the entry to retrieve - \param type - \param name - \param length - \param offset - \param list */ - -void RIFFFile::GetDirectoryEntry( int i, FOURCC &type, FOURCC &name, off_t &length, off_t &offset, int &list ) const -{ - RIFFDirEntry entry; - - assert( i >= 0 && i < ( int ) directory.size() ); - - entry = directory[ i ]; - type = entry.type; - name = entry.name; - length = entry.length; - offset = entry.offset; - list = entry.parent; -} - - -/** Retrieves an entry. - - Gets the whole RIFFDirEntry object. - - \param i the ID of the entry to retrieve - \return the entry */ - -RIFFDirEntry RIFFFile::GetDirectoryEntry( int i ) const -{ - assert( i >= 0 && i < ( int ) directory.size() ); - - return directory[ i ]; -} - - -/** Calculates the total size of the file - - \return the size the file in bytes -*/ - -off_t RIFFFile::GetFileSize( void ) const -{ - - /* If we have at least one entry, return the length field - of the FILE entry, which is the length of its contents, - which is the actual size of whatever is currently in the - AVI directory structure. - - Note that the first entry does not belong to the AVI - file. - - If we don't have any entry, the file size is zero. */ - - if ( directory.size() > 0 ) - return directory[ 0 ].length; - else - return 0; -} - - -/** prints the attributes of the entry - - \param i the ID of the entry to print -*/ - -void RIFFFile::PrintDirectoryEntry ( int i ) const -{ - RIFFDirEntry entry; - RIFFDirEntry parent; - FOURCC entry_name; - FOURCC list_name; - - /* Get all attributes of the chunk object. If it is contained - in a list, get the name of the list too (otherwise the name of - the list is blank). If the chunk object doesn´t have a name (only - LISTs and RIFFs have a name), the name is blank. */ - - entry = GetDirectoryEntry( i ); - if ( entry.parent != RIFF_NO_PARENT ) - { - parent = GetDirectoryEntry( entry.parent ); - list_name = parent.name; - } - else - { - list_name = make_fourcc( " " ); - } - if ( entry.name != 0 ) - { - entry_name = entry.name; - } - else - { - entry_name = make_fourcc( " " ); - } - - /* Print out the ascii representation of type and name, as well as - length and file offset. */ - - cout << hex << setfill( '0' ) << "type: " - << ((char *)&entry.type)[0] - << ((char *)&entry.type)[1] - << ((char *)&entry.type)[2] - << ((char *)&entry.type)[3] - << " name: " - << ((char *)&entry_name)[0] - << ((char *)&entry_name)[1] - << ((char *)&entry_name)[2] - << ((char *)&entry_name)[3] - << " length: 0x" << setw( 12 ) << entry.length - << " offset: 0x" << setw( 12 ) << entry.offset - << " list: " - << ((char *)&list_name)[0] - << ((char *)&list_name)[1] - << ((char *)&list_name)[2] - << ((char *)&list_name)[3] << dec << endl; - - /* print the content itself */ - - PrintDirectoryEntryData( entry ); -} - - -/** prints the contents of the entry - - Prints a readable representation of the contents of an index. - Override this to print out any objects you store in the RIFF file. - - \param entry the entry to print */ - -void RIFFFile::PrintDirectoryEntryData( const RIFFDirEntry &entry ) const - {} - - -/** prints the contents of the whole directory - - Prints a readable representation of the contents of an index. - Override this to print out any objects you store in the RIFF file. - - \param entry the entry to print */ - -void RIFFFile::PrintDirectory() const -{ - int i; - int count = directory.size(); - - for ( i = 0; i < count; ++i ) - PrintDirectoryEntry( i ); -} - - -/** finds the index - - finds the index of a given directory entry type - - \todo inefficient if the directory has lots of items - \param type the type of the entry to find - \param n the zero-based instance of type to locate - \return the index of the found object in the directory, or -1 if not found */ - -int RIFFFile::FindDirectoryEntry ( FOURCC type, int n ) const -{ - int i, j = 0; - int count = directory.size(); - - for ( i = 0; i < count; ++i ) - if ( directory[ i ].type == type ) - { - if ( j == n ) - return i; - j++; - } - - return -1; -} - - -/** Reads all items that are contained in one list - - Read in one chunk and add it to the directory. If the chunk - happens to be of type LIST, then call ParseList recursively for - it. - - \param parent The id of the item to process -*/ - -void RIFFFile::ParseChunk( int parent ) -{ - FOURCC type; - DWORD length; - int typesize; - - /* Check whether it is a LIST. If so, let ParseList deal with it */ - - fail_if( read( fd, &type, sizeof( type ) ) != sizeof( type )); - if ( type == make_fourcc( "LIST" ) ) - { - typesize = (int) -sizeof( type ); - fail_if( lseek( fd, typesize, SEEK_CUR ) == ( off_t ) - 1 ); - ParseList( parent ); - } - - /* it is a normal chunk, create a new directory entry for it */ - - else - { - fail_neg( read( fd, &length, sizeof( length ) ) ); - if ( length & 1 ) - length++; - AddDirectoryEntry( type, 0, length, parent ); - fail_if( lseek( fd, length, SEEK_CUR ) == ( off_t ) - 1 ); - } -} - - -/** Reads all items that are contained in one list - - \param parent The id of the list to process - -*/ - -void RIFFFile::ParseList( int parent ) -{ - FOURCC type; - FOURCC name; - int list; - DWORD length; - off_t pos; - off_t listEnd; - - /* Read in the chunk header (type and length). */ - fail_neg( read( fd, &type, sizeof( type ) ) ); - fail_neg( read( fd, &length, sizeof( length ) ) ); - - if ( length & 1 ) - length++; - - /* The contents of the list starts here. Obtain its offset. The list - name (4 bytes) is already part of the contents). */ - - pos = lseek( fd, 0, SEEK_CUR ); - fail_if( pos == ( off_t ) - 1 ); - fail_neg( read( fd, &name, sizeof( name ) ) ); - - /* Add an entry for this list. */ - - list = AddDirectoryEntry( type, name, sizeof( name ), parent ); - - /* Read in any chunks contained in this list. This list is the - parent for all chunks it contains. */ - - listEnd = pos + length; - while ( pos < listEnd ) - { - ParseChunk( list ); - pos = lseek( fd, 0, SEEK_CUR ); - fail_if( pos == ( off_t ) - 1 ); - } -} - - -/** Reads the directory structure of the whole RIFF file - -*/ - -void RIFFFile::ParseRIFF( void ) -{ - FOURCC type; - DWORD length; - off_t filesize = 0; - off_t pos; - int container = AddDirectoryEntry( make_fourcc( "FILE" ), make_fourcc( "FILE" ), 0, RIFF_NO_PARENT ); - - pos = lseek( fd, 0, SEEK_SET ); - fail_if( pos == -1 ); - - /* calculate file size from RIFF header instead from physical file. */ - - while ( ( read( fd, &type, sizeof( type ) ) > 0 ) && - ( read( fd, &length, sizeof( length ) ) > 0 ) && - ( type == make_fourcc( "RIFF" ) ) ) - { - - filesize += length + RIFF_HEADERSIZE; - - fail_if( lseek( fd, pos, SEEK_SET ) == ( off_t ) - 1 ); - ParseList( container ); - pos = lseek( fd, 0, SEEK_CUR ); - fail_if( pos == ( off_t ) - 1 ); - } -} - - -/** Reads one item including its contents from the RIFF file - - \param chunk_index The index of the item to write - \param data A pointer to the data - -*/ - -void RIFFFile::ReadChunk( int chunk_index, void *data, off_t data_len ) -{ - RIFFDirEntry entry; - - entry = GetDirectoryEntry( chunk_index ); - pthread_mutex_lock( &file_mutex ); - fail_if( lseek( fd, entry.offset, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( read( fd, data, entry.length > data_len ? data_len : entry.length ) ); - pthread_mutex_unlock( &file_mutex ); -} - - -/** Writes one item including its contents to the RIFF file - - \param chunk_index The index of the item to write - \param data A pointer to the data - -*/ - -void RIFFFile::WriteChunk( int chunk_index, const void *data ) -{ - RIFFDirEntry entry; - - entry = GetDirectoryEntry( chunk_index ); - pthread_mutex_lock( &file_mutex ); - fail_if( lseek( fd, entry.offset - RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 ); - fail_neg( write( fd, &entry.type, sizeof( entry.type ) ) ); - DWORD length = entry.length; - fail_neg( write( fd, &length, sizeof( length ) ) ); - fail_neg( write( fd, data, entry.length ) ); - pthread_mutex_unlock( &file_mutex ); - - /* Remember that this entry already has been written. */ - - directory[ chunk_index ].written = true; -} - - -/** Writes out the directory structure - - For all items in the directory list that have not been written - yet, it seeks to the file position where that item should be - stored and writes the type and length field. If the item has a - name, it will also write the name field. - - \note It does not write the contents of any item. Use WriteChunk to do that. */ - -void RIFFFile::WriteRIFF( void ) -{ - int i; - RIFFDirEntry entry; - int count = directory.size(); - - /* Start at the second entry (RIFF), since the first entry (FILE) - is needed only for internal purposes and is not written to the - file. */ - - for ( i = 1; i < count; ++i ) - { - - /* Only deal with entries that haven´t been written */ - - entry = GetDirectoryEntry( i ); - if ( entry.written == false ) - { - - /* A chunk entry consist of its type and length, a list - entry has an additional name. Look up the entry, seek - to the start of the header, which is at the offset of - the data start minus the header size and write out the - items. */ - - fail_if( lseek( fd, entry.offset - RIFF_HEADERSIZE, SEEK_SET ) == ( off_t ) - 1 ) ; - fail_neg( write( fd, &entry.type, sizeof( entry.type ) ) ); - DWORD length = entry.length; - fail_neg( write( fd, &length, sizeof( length ) ) ); - - /* If it has a name, it is a list. Write out the extra name - field. */ - - if ( entry.name != 0 ) - { - fail_neg( write( fd, &entry.name, sizeof( entry.name ) ) ); - } - - /* Remember that this entry already has been written. */ - - directory[ i ].written = true; - } - } -} diff --git a/src/modules/kino/riff.h b/src/modules/kino/riff.h deleted file mode 100644 index 810056326..000000000 --- a/src/modules/kino/riff.h +++ /dev/null @@ -1,143 +0,0 @@ -/* -* riff.h library for RIFF file format i/o -* Copyright (C) 2000 - 2002 Arne Schirmacher -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -* -* Tag: $Name$ -* -* Change log: -* -* $Log$ -* Revision 1.2 2005/07/25 07:21:39 lilo_booter -* + fixes for opendml dv avi -* -* Revision 1.1 2005/04/15 14:28:26 lilo_booter -* Initial version -* -* Revision 1.14 2005/04/01 23:43:10 ddennedy -* apply endian fixes from Daniel Kobras -* -* Revision 1.13 2004/10/11 01:37:11 ddennedy -* mutex safety locks in RIFF and AVI classes, type 2 AVI optimization, mencoder export script -* -* Revision 1.12 2004/01/06 22:53:42 ddennedy -* metadata editing tweaks and bugfixes, new ui elements in preparation for publish functions -* -* Revision 1.11 2003/11/25 23:01:25 ddennedy -* cleanup and a few bugfixes -* -* Revision 1.10 2003/10/21 16:34:34 ddennedy -* GNOME2 port phase 1: initial checkin -* -* Revision 1.8.4.1 2002/11/25 04:48:31 ddennedy -* bugfix to report errors when loading files -* -* Revision 1.8 2002/04/21 06:36:40 ddennedy -* kindler avc and 1394 bus reset support in catpure page, honor max file size -* -* Revision 1.7 2002/04/09 06:53:42 ddennedy -* cleanup, new libdv 0.9.5, large AVI, dnd storyboard -* -* Revision 1.3 2002/03/25 21:34:25 arne -* Support for large (64 bit) files mostly completed -* -* Revision 1.2 2002/03/04 19:22:43 arne -* updated to latest Kino avi code -* -* Revision 1.1.1.1 2002/03/03 19:08:08 arne -* import of version 1.01 -* -*/ - -#ifndef _RIFF_H -#define _RIFF_H 1 - -#include -using std::vector; - -#include - -#include "endian_types.h" - -#define QUADWORD int64_le_t -#define DWORD int32_le_t -#define LONG u_int32_le_t -#define WORD int16_le_t -#define BYTE u_int8_le_t -#define FOURCC u_int32_t // No endian conversion needed. - -#define RIFF_NO_PARENT (-1) -#define RIFF_LISTSIZE (4) -#define RIFF_HEADERSIZE (8) - -#ifdef __cplusplus -extern "C" -{ - FOURCC make_fourcc( const char * s ); -} -#endif - -class RIFFDirEntry -{ -public: - FOURCC type; - FOURCC name; - off_t length; - off_t offset; - int parent; - int written; - - RIFFDirEntry(); - RIFFDirEntry( FOURCC t, FOURCC n, int l, int o, int p ); -}; - - -class RIFFFile -{ -public: - RIFFFile(); - RIFFFile( const RIFFFile& ); - virtual ~RIFFFile(); - RIFFFile& operator=( const RIFFFile& ); - - virtual bool Open( const char *s ); - virtual bool Create( const char *s ); - virtual void Close(); - virtual int AddDirectoryEntry( FOURCC type, FOURCC name, off_t length, int list ); - virtual void SetDirectoryEntry( int i, FOURCC type, FOURCC name, off_t length, off_t offset, int list ); - virtual void SetDirectoryEntry( int i, RIFFDirEntry &entry ); - virtual void GetDirectoryEntry( int i, FOURCC &type, FOURCC &name, off_t &length, off_t &offset, int &list ) const; - virtual RIFFDirEntry GetDirectoryEntry( int i ) const; - virtual off_t GetFileSize( void ) const; - virtual void PrintDirectoryEntry( int i ) const; - virtual void PrintDirectoryEntryData( const RIFFDirEntry &entry ) const; - virtual void PrintDirectory( void ) const; - virtual int FindDirectoryEntry( FOURCC type, int n = 0 ) const; - virtual void ParseChunk( int parent ); - virtual void ParseList( int parent ); - virtual void ParseRIFF( void ); - virtual void ReadChunk( int chunk_index, void *data, off_t data_len ); - virtual void WriteChunk( int chunk_index, const void *data ); - virtual void WriteRIFF( void ); - -protected: - int fd; - pthread_mutex_t file_mutex; - -private: - vector directory; -}; -#endif diff --git a/src/modules/linsys/20-linsys.rules b/src/modules/linsys/20-linsys.rules deleted file mode 100644 index 2f4f06db3..000000000 --- a/src/modules/linsys/20-linsys.rules +++ /dev/null @@ -1,6 +0,0 @@ -# udev rules for linsys cards to give members of the video group permissions -KERNEL=="sdi*[rt]x[0-9]*", MODE="0660", GROUP="video", \ - RUN+="/usr/bin/find /sys/$env{DEVPATH}/ -type f -execdir /bin/chmod 0660 {} + -execdir /bin/chgrp video {} +", OPTIONS="last_rule" -KERNEL=="asi*[rt]x[0-9]*", MODE="0660", GROUP="video", \ - RUN+="/usr/bin/find /sys/$env{DEVPATH}/ -type f -execdir /bin/chmod 0660 {} + -execdir /bin/chgrp video {} +", OPTIONS="last_rule" - diff --git a/src/modules/linsys/Makefile b/src/modules/linsys/Makefile deleted file mode 100755 index 143cb9d6e..000000000 --- a/src/modules/linsys/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -CFLAGS += -I../.. - -LDFLAGS += -L../../framework -lmlt -lpthread - -include ../../../config.mak -include config.mak - -TARGET = ../libmltlinsys$(LIBSUF) - -OBJS = factory.o \ - consumer_SDIstream.o - -ifdef WITH_JPEG -CFLAGS += -DWITH_JPEG -LDFLAGS += -ljpeg -endif - -SRCS := $(OBJS:.o=.c) - -all: $(TARGET) - -$(TARGET): $(OBJS) - $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) - -depend: $(SRCS) - $(CC) -MM $(CFLAGS) $^ 1>.depend - -distclean: clean - rm -f .depend - -clean: - rm -f $(OBJS) $(TARGET) - -install: all - install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" - install -d "$(DESTDIR)$(mltdatadir)/linsys" - install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/linsys" - -ifneq ($(wildcard .depend),) -include .depend -endif diff --git a/src/modules/linsys/configure b/src/modules/linsys/configure deleted file mode 100755 index 735daeed9..000000000 --- a/src/modules/linsys/configure +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh - -if [ "$help" = "1" ] -then - cat << EOF -Linsys options: - - --linsys-with-jpeg - Enable the option to export JPEGs (disabled by default) - -EOF - -else - if [ "$targetos" = "Darwin" ] || [ "$targetos" = "MinGW" ] - then - echo "- does not build on OS X or Windows: disabling" - touch ../disable-linsys - exit 0 - fi - - touch config.mak - - for i in "$@" - do - case $i in - --linsys-with-jpeg ) echo "WITH_JPEG=1" > config.mak ;; - esac - done - - exit 0 -fi - diff --git a/src/modules/linsys/consumer_SDIstream.c b/src/modules/linsys/consumer_SDIstream.c deleted file mode 100644 index a00e74a30..000000000 --- a/src/modules/linsys/consumer_SDIstream.c +++ /dev/null @@ -1,672 +0,0 @@ -/** - * - * MLT SDI Consumer: - * request video and audio data from MLT and generate an SDI stream - * - * Copyright (C) Broadcasting Center Europe S.A. http://www.bce.lu - * an RTL Group Company http://www.rtlgroup.com - * All rights reserved. - * - * E-mail: support_plasec@bce.lu - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * - * DESCRIPTION: - * This software act as interface between the MLT Frameworkas as - * MLT Consumer and the Linear Systems Ltd. SMPTE 292M and SMPTE 259M-C boards. - * - * Linear Systems can be contacted at http://www.linsys.ca - * - ********************************************************************************** - * System : INTeL I686 64Bit - * OS : Linux SuSE Kernel 2.6.27.39-0.2-default - * Compiler: gcc 4.3.2 (c++) - ********************************************************************************** - * Project : MLT SDI Consumer for SD and HD - * Started by : Thomas Kurpick, Dipl.Inf. (FH) - ********************************************************************************** - * Supported and tested boards for SD-SDI or HD-SDI Output: - * PCI SDI Masterâ„¢ (model 107) - * PCIe SDI Masterâ„¢ (model 159) - * PCIe LP SDI Masterâ„¢ FD (model 145) - * PCIe LP SDI Masterâ„¢ Quad/o (model 180) - * PCIe LP HD-SDI Masterâ„¢ O (model 193) - * - * Note: PCIe LP HD-SDI Masterâ„¢ O (model 193) is an VidPort model and supports an - * separate video and audio interface. Device file: - * /dev/sdivideotx[] for active video data - * /dev/sdiaudiotx[] for pcm audio data - * - * This mlt consumer use the following device files: - * /dev/sditx[] (SD-PAL) up to 8 x AES (8 x stereo / 16 audio channels) - * /dev/sdivideotx[] (HD) - * /dev/sdiaudiotx[] (HD) up to 4 x AES (4 x stereo / 8 audio channels) - * - * - ********************************************************************************** - * Last modified by: - * Thomas Kurpick 08.Jan.2010 - * and - * Dan Dennedy 10.Feb.2010 - * Ver. 2.0 - * See also Git commit log. - * - ********************************************************************************** - * - * Consumer properties: - * 'dev_video' - * 'dev_audio' - * 'blanking' - * Only to monitor the SDI output a beta version of jpeg-writer is implemented. - * 'jpeg_files' a number for output interval - * 'save_jpegs' path for image - * - * EXAMPLE: - * - * SDI boards with full frame stream (with blanking): - * melt video.dv -consumer sdi:/dev/sditx0 - * melt video.dv -consumer sdi:/dev/sditx0 blanking=true - * melt video.dv -consumer sdi dev_video=/dev/sditx0 blanking=true - * melt video.dv audio_index=all -consumer sdi dev_video=/dev/sditx0 blanking=true - * - * SDI boards without full frame stream (without blanking): - * melt -profile atsc_1080i_50 video.mpeg audio_index=1 -consumer sdi dev_video=/dev/sdivideotx0 dev_audio=/dev/sdiaudiotx0 blanking=false - * melt -profile atsc_1080i_50 video.mpeg audio_index=all -consumer sdi dev_video=/dev/sdivideotx0 dev_audio=/dev/sdiaudiotx0 blanking=false - * melt -profile atsc_1080i_50 video.mpeg audio_index=all -consumer sdi dev_video=/dev/sdivideotx0 dev_audio=/dev/sdiaudiotx0 blanking=false jpeg_files=25 save_jpegs=channel_04.jpg - * - * - * SDI output formats and MLT profiles: - * ##################################################################################################################################################### - * ########## SMPTE 274M 1920 x 1080 Image Sample Structure ############################################################################################ - * ##################################################################################################################################################### - * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model) - * 4 1920 x 1080/60/I interlaced 30 HZ 4 x AES (8 channels) atsc_1080i_60 193 - * 5 1920 x 1080/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080i_5994 193 - * 6 1920 x 1080/50/I interlaced 25 HZ 4 x AES (8 channels) atsc_1080i_50 193 - * 7 1920 x 1080/30/P progressive 30 HZ 4 x AES (8 channels) atsc_1080p_30 193 - * 8 1920 x 1080/29.97/P progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080p_2997 193 - * 9 1920 x 1080/25/P progressive 25 HZ 4 x AES (8 channels) atsc_1080p_25 193 - * 10 1920 x 1080/24/P progressive 24 HZ 4 x AES (8 channels) atsc_1080p_24 193 - * 11 1920 x 1080/23.98/P progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_1080p_2398 193 - * - * ##################################################################################################################################################### - * ########## SMPTE 296M 1280 × 720 Progressive Image Sample Structure ################################################################################# - * ##################################################################################################################################################### - * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model) - * 1 1280 × 720/60 progressive 60 HZ 4 x AES (8 channels) atsc_720p_60 193 - * 2 1280 × 720/59.94 progressive 60000/1001 ~ 59.97 HZ 4 x AES (8 channels) atsc_720p_5994 193 - * 3 1280 × 720/50 progressive 50 HZ 4 x AES (8 channels) atsc_720p_50 193 - * 4 1280 × 720/30 progressive 30 HZ 4 x AES (8 channels) atsc_720p_30 193 - * 5 1280 × 720/29.97 progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_720p_2997 193 - * 6 1280 × 720/25 progressive 25 HZ 4 x AES (8 channels) atsc_720p_25 193 - * 7 1280 × 720/24 progressive 24 HZ 4 x AES (8 channels) atsc_720p_24 193 - * 8 1280 × 720/23.98 progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_720p_2398 193 - * - * ##################################################################################################################################################### - * ########## SMPTE 125M 486i 29.97Hz & BT.656 576i 25Hz ############################################################################################### - * ##################################################################################################################################################### - * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model) - * SD PAL 720 × 576/50/I interlaced 25 HZ 8 x AES (16 channels) dv_pal 180,145,159,107 - * SD PAL 720 × 576/50/I interlaced 25 HZ 4 x AES (8 channels) dv_pal 193 - * SD NTSC 720 × 486/59.94/I interlaced 30000/1001 ~ 29.97 HZ 8 x AES (16 channels) sdi_486i_5994 TODO:180,145,159,107 - * SD NTSC 720 × 486/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) sdi_486i_5994 193 - * - **/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef WITH_JPEG -// for JPEG output -#include -#endif - -#include "sdi_generator.c" - -// alias for "struct consumer_SDIstream_s *" , now we can write "consumer_SDIstream". Makes it more readable... -typedef struct consumer_SDIstream_s *consumer_SDIstream; - -struct consumer_SDIstream_s { - // Most of these values are set to their defaults by the parent consumer - struct mlt_consumer_s parent; // This is the basic Consumer from which we fetch our data - mlt_image_format pix_fmt; // Must be mlt_image_yuv422 for SDI - - int width; - int height; - - struct audio_format audio_format; - /** - * device file: - * /dev/sditx0 - * /dev/sdivideotx0 - * /dev/sdiaudiotx0 - **/ - char *device_file_video; // Path for SDI output - char *device_file_audio; // Path for exclusive SDI audio output - - /** - * write own HANC (ancillary data) is available for: - * SDI board ASSY 193 HD 'blanking=false' - * SDI board ASSY 180 SD quad 'blanking=true' - * SDI board ASSY 145 SD single 'blanking=true' - * - * 0=false, 1=true - * - **/ - uint8_t blanking; - - // our audio channel pair for this frame - int16_t audio_buffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES]; // The SDI audio channel pairs for this frame - - char *video_fmt_name; // 1080i25, 1080p25, 576i50, 486i2997, ... - -}; - -/** - * Forward references to static functions. - **/ -static int consumer_start(mlt_consumer this); -static int consumer_stop(mlt_consumer this); -static int consumer_is_stopped(mlt_consumer this); -static void consumer_close(mlt_consumer parent); -static void *consumer_thread(void *); - -static void consumer_write_JPEG(char * path, uint8_t **vBuffer, mlt_profile myProfile); -int convertYCBCRtoRGB(int y1, int cb, int cr, int y2, uint8_t * target_rgb); - -/***************************************************************************************************** - ****************************************** SDI Master Consumer ************************************** - *****************************************************************************************************/ - -/** This is what will be called by the factory - * @param profile: profile name for consumer - * @param type: unused - * @param *id: unused - * @param *arg: pointer to output path - **/ -mlt_consumer consumer_SDIstream_init(mlt_profile profile, mlt_service_type type, const char *id, char *arg) { - - // Create the consumer object - consumer_SDIstream this = calloc( 1, sizeof(struct consumer_SDIstream_s) ); - - // If malloc and consumer init ok - if (this != NULL && mlt_consumer_init(&this->parent, this, profile) == 0) { - - // Get the parent consumer object - mlt_consumer parent = &this->parent; - - // We have stuff to clean up, so override the close method - parent->close = consumer_close; - - // Set output path for SDI, default is "/dev/sditx0" - if (arg == NULL) { - this->device_file_video = strdup("/dev/sditx0"); - } else { - this->device_file_video = strdup(arg); - } - - // Set up start/stop/terminated callbacks - parent->start = consumer_start; - parent->stop = consumer_stop; - parent->is_stopped = consumer_is_stopped; - - // Set explicit to zero or other value - int i, j; - for (i = 0; i < MAX_AUDIO_STREAMS; i++) { - for (j = 0; j < MAX_AUDIO_SAMPLES; j++) { - this->audio_buffer[i][j] = j; - } - } - - mlt_events_register( MLT_CONSUMER_PROPERTIES(parent), "consumer-fatal-error", NULL ); - - // Return the consumer produced - return parent; - } - - // malloc or consumer init failed - free(this); - - // Indicate failure - return NULL; -} - -/** - * Start the consumer. - **/ -static int consumer_start(mlt_consumer parent) { - - // Get the properties - mlt_properties properties = mlt_consumer_properties(parent); - - // Get the actual object - consumer_SDIstream this = parent->child; - - // Check that we're not already running - if (!mlt_properties_get_int(properties, "running")) { - // Allocate threads - pthread_t *consumer_pthread = calloc(1, sizeof(pthread_t)); - - // Assign the thread to properties - mlt_properties_set_data(properties, "consumer_pthread", consumer_pthread, sizeof(pthread_t), free, NULL); - - // Set the running state - mlt_properties_set_int(properties, "running", 1); - - // Create the the threads - pthread_create(consumer_pthread, NULL, consumer_thread, this); - } - return 0; -} - -/** - * Stop the consumer - **/ -static int consumer_stop(mlt_consumer parent) { - - // Get the properties - mlt_properties properties = mlt_consumer_properties(parent); - - // Check that we're running - if (mlt_properties_get_int(properties, "running")) { - - // Get the threads - pthread_t *consumer_pthread = mlt_properties_get_data(properties, "consumer_pthread", NULL); - - // Stop the threads - mlt_properties_set_int(properties, "running", 0); - - // Wait for termination - pthread_join(*consumer_pthread, NULL); - - } - return 0; -} - -/** - * Determine if the consumer is stopped - **/ -static int consumer_is_stopped(mlt_consumer this) { - // Get the properties - mlt_properties properties = mlt_consumer_properties(this); - return !mlt_properties_get_int(properties, "running"); -} - -/** - * Threaded wrapper for pipe. - **/ -static void *consumer_thread(void *arg) { - - // Identify the arg - consumer_SDIstream this = arg; - - // Get the consumer - mlt_consumer consumer = &this->parent; - - // Convenience functionality (this is to stop melt/inigo after the end of a playout) - int terminate_on_pause = mlt_properties_get_int(MLT_CONSUMER_PROPERTIES( consumer ), "terminate_on_pause"); - int terminated = 0; // save only status - - int save_jpegs = mlt_properties_get_int(MLT_CONSUMER_PROPERTIES( consumer ), "save_jpegs"); - char * jpeg_folder = mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "jpeg_file"); - - // If no folder is specified, skip jpeg export - if (jpeg_folder == NULL) { - save_jpegs = 0; - } - - if (save_jpegs > 0) - mlt_log_info(MLT_CONSUMER_SERVICE(consumer), "Saving a JPEG every %i frame.\n", save_jpegs); - - int counter = 0; // each second we save a Jpeg - - // set properties (path) for device files - if (mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "dev_video") != NULL) { - this->device_file_video = strdup(mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "dev_video")); - } - if (mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "dev_audio") != NULL) { - if (this->blanking == 0) { - this->device_file_audio = strdup(mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "dev_audio")); - } else { - // if we write HANC we do not write further audio data - mlt_log_info(MLT_CONSUMER_SERVICE(consumer), "Audio device file is set but will not be used.\n"); - } - } - - // Set additional device file defaults - struct stat st; - int fd = -1; - if (this->device_file_video) - fd = stat(this->device_file_video, &st); - if (fd == -1) { - free(this->device_file_video); - this->device_file_video = strdup("/dev/sdivideotx0"); - } else { - close(fd); - } - if (this->device_file_audio) { - fd = stat(this->device_file_audio, &st); - if (fd == -1) { - free(this->device_file_audio); - this->device_file_audio = strdup("/dev/sdiaudiotx0"); - } else { - close(fd); - } - } else if (this->device_file_video && - strstr(this->device_file_video, "sdivideotx")) { - this->device_file_audio = strdup("/dev/sdiaudiotx0"); - } - - // set blanking flag; is not nessary we write no own blanking(HANC) for HD board ASSY 193 - if (mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "blanking")) { - // set value - if (!strcmp( mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "blanking"), "false")) { - this->blanking = 0; - } else if (!strcmp( mlt_properties_get(MLT_CONSUMER_PROPERTIES( consumer ), "blanking"), "true")) { - this->blanking = 1; - } else { - this->blanking = mlt_properties_get_int(MLT_CONSUMER_PROPERTIES( consumer ), "blanking"); - } - } else if (this->device_file_video && strstr(this->device_file_video, "sdivideotx")) { - this->blanking = 0; - } else { - // set default value without HD board, also with blanking - this->blanking = 1; - } - - // Define a frame pointer - mlt_frame frame; - - // set Datablock number for SDI encoding - int my_dbn = 1; - - double fps = mlt_properties_get_double(MLT_CONSUMER_PROPERTIES(consumer), "fps"); - unsigned int count = 0; - - // Tell the framework how we want our audio and video - int frequency = this->audio_format.sample_rate; - int channels = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES(consumer), "channels" ); - int samples; - - // set number of audio channels, linsys vidport model 193 is limited to 8 channels (4AES frames) - this->audio_format.channels = 8; /* 0,2,4,6,8 */ - this->audio_format.aformat = mlt_audio_s16; /* 16, 24, 32 */ - this->audio_format.sample_rate = 48000; - this->pix_fmt = mlt_image_yuv422; - - if (this->device_file_video && this->device_file_audio && - !sdi_init(this->device_file_video, this->device_file_audio, this->blanking, mlt_service_profile((mlt_service) consumer), &this->audio_format)) { - mlt_log_fatal( MLT_CONSUMER_SERVICE(consumer), "failed to initialize\n" ); - mlt_events_fire( MLT_CONSUMER_PROPERTIES(consumer), "consumer-fatal-error", NULL ); - mlt_consumer_stopped(consumer); - return NULL; - } - - uint8_t *video_buffer = NULL; - int16_t *audio_buffer_tmp; // the upstream audio buffer - - // Loop until told not to - while (!consumer_is_stopped(consumer) && terminated == 0) { // - - // Get a frame from the service - if ((frame = mlt_consumer_rt_frame(consumer)) != NULL) { - - // Check for termination - if (terminate_on_pause && frame != NULL) { - terminated = mlt_properties_get_double(MLT_FRAME_PROPERTIES( frame ), "_speed") == 0.0; - if (terminated == 1) { - mlt_log_verbose(MLT_CONSUMER_SERVICE(consumer), "\nEnd of playout reached, terminating\n"); - consumer_stop(consumer); - } - } - - // True if mlt_consumer_rt_frame(...) successful - if (mlt_properties_get_int(mlt_frame_properties(frame), "rendered") == 1) { - - // Get the video from this frame and save it to our video_buffer - mlt_frame_get_image(frame, &video_buffer, &this->pix_fmt, &this->width, &this->height, 1); - - // Get the audio from this frame and save it to our audio_buffer - samples = mlt_audio_calculate_frame_samples(fps, frequency, count++); - mlt_frame_get_audio(frame, (void**) &audio_buffer_tmp, &this->audio_format.aformat, &frequency, &channels, &samples); - - this->audio_format.sample_rate = frequency; - this->audio_format.samples = samples; - - /* TODO: Audio is currently hard coded to 8 channels because write 8 channels to the sdi board. - The Linys SDI board has to be configured with the same number of channels! - this->audio_format.channels = channels; // take given number of channels - */ - - /* Tell the sdi_generator.c to playout our frame - * 8 AES (8 x stereo channels are possible, max. 16 channels) Linsys SD board model: 107, 159, 145, 180 - * 4 AES (4 x stereo channels are possible, max. 8 channels) Linsys HD board model: 193 - */ - if (video_buffer) { - - // provide mapping of audio channels - int i, j = 0; - int map_channels, map_start; - - for (i = 0; i < MAX_AUDIO_STREAMS && j < channels; i++) { - char key[27]; - int c; - - sprintf(key, "meta.map.audio.%d.channels", i); - map_channels = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), key); - sprintf(key, "meta.map.audio.%d.start", i); - map_start = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), key); - - if (!map_channels) - map_channels = channels - j; - for (c = 0; c < map_channels && j < channels; c++, j++) { - int16_t *src = audio_buffer_tmp + j; - int16_t *dest = this->audio_buffer[(map_start + c) / 2] + (map_start + c) % 2; - int s = samples + 1; - - while (--s) { - *dest = *src; - dest += 2; - src += channels; - } - } - } - - // generate SDI frame and playout - my_dbn = sdi_playout(video_buffer, this->audio_buffer, &this->audio_format, (channels + 1) / 2, my_dbn); - - // write a JPEG of every X-th frame - if (save_jpegs > 0 && counter >= save_jpegs) { - consumer_write_JPEG(jpeg_folder, &video_buffer, mlt_service_profile((mlt_service) consumer)); - counter = 0; - } else if (save_jpegs > 0) { - counter++; - } - mlt_events_fire(MLT_CONSUMER_PROPERTIES( consumer ), "consumer-frame-show", frame, NULL ); - } else { - mlt_log_warning(MLT_CONSUMER_SERVICE(consumer), "Videobuffer was NULL, skipping playout!\n"); - } - } else { - mlt_log_warning(MLT_CONSUMER_SERVICE(consumer), "WARNING the requested frame is not yet rendered! This will cause image disturbance!\n"); - - if (video_buffer) { - my_dbn = sdi_playout(video_buffer, this->audio_buffer, &this->audio_format, (channels + 1) / 2, my_dbn); - } else { - mlt_log_warning(MLT_CONSUMER_SERVICE(consumer), "Videobuffer was NULL, skipping playout!\n"); - } - } - - if (frame != NULL) - mlt_frame_close(frame); - } - - } - mlt_consumer_stopped(consumer); - return NULL; -} - -/** - * Callback to allow override of the close method. - **/ -static void consumer_close(mlt_consumer parent) { - - // Get the actual object - consumer_SDIstream this = parent->child; - - free(this->device_file_video); - free(this->device_file_audio); - - // Now clean up the rest (the close = NULL is a bit nasty but needed for now) - parent->close = NULL; - mlt_consumer_close(parent); - - // Invoke the close function of the sdi_generator to close opened files used for output - sdimaster_close(); - - // Finally clean up this - free(this); -} - -/** - * Write videobuffer as JPEG to path - * @param path - **/ -static void consumer_write_JPEG(char * filename, uint8_t **vBuffer, mlt_profile myProfile) { - -#ifdef WITH_JPEG - - int bytes_per_pixel = 3; // or 1 for GRACYSCALE images - int color_space = JCS_RGB; // or JCS_GRAYSCALE for grayscale images - - uint8_t * buffer_position = *vBuffer; - uint8_t image_rgb[myProfile->width * myProfile->height * bytes_per_pixel]; - - //convert vBuffer to RGB - int i; - for (i = 0; i < sizeof(image_rgb) / 6; i++) { - int y1 = *(buffer_position++); - int cb = *(buffer_position++); - int y2 = *(buffer_position++); - int cr = *(buffer_position++); - convertYCBCRtoRGB(y1, cb, cr, y2, &image_rgb[i * 6]); - } - - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - - // this is a pointer to one row of image data - JSAMPROW row_pointer[1]; - - FILE *outfile = fopen(filename, "wb"); - - if (!outfile) { - mlt_log_error(NULL, "%s: Error opening output jpeg file %s\n!", __FILE__, filename); - return; - } - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); - jpeg_stdio_dest(&cinfo, outfile); - - // Setting the parameters of the output file here - cinfo.image_width = myProfile->width; - cinfo.image_height = myProfile->height; - cinfo.input_components = bytes_per_pixel; - cinfo.in_color_space = (J_COLOR_SPACE) color_space; - - // default compression parameters, we shouldn't be worried about these - jpeg_set_defaults(&cinfo); - - // Now do the compression - jpeg_start_compress(&cinfo, TRUE); - - // like reading a file, this time write one row at a time - while (cinfo.next_scanline < cinfo.image_height) { - row_pointer[0] = &image_rgb[cinfo.next_scanline * cinfo.image_width * cinfo.input_components]; - jpeg_write_scanlines(&cinfo, row_pointer, 1); - } - // similar to read file, clean up after we're done compressing - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); - fclose(outfile); -#endif -} - -/** - * converts YCbCr samples to two 32-bit RGB values - * @param y1 cb cr and y2 values - * @param target pointer - * @return 0 upon success - **/ -int convertYCBCRtoRGB(int y1, int cb, int cr, int y2, uint8_t * target_rgb) { - -#ifdef WITH_JPEG - - if(y1 > 235) - y1 = 235; - if(y1 < 16) - y1 = 16; - - if(y2 > 235) - y2 = 235; - if(y2 < 16) - y2 = 16; - - if(cr > 240) - cr = 240; - if(cr < 16) - cr = 16; - - if(cb > 240) - cb = 240; - if(cb < 16) - cb = 16; - - uint8_t r1, g1, b1, r2, g2, b2; - - //pointer to current output buffer position - uint8_t * target_pointer = target_rgb; - - r1 = y1 + 1.402 * (cr - 128); - g1 = y1 - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); - b1 = y1 + 1.772 * (cb - 128); - - r2 = y2 + 1.402 * (cr - 128); - g2 = y2 - 0.34414 * (cb - 128) - 0.71414 *(cr - 128); - b2 = y2 + 1.772 * (cb - 128); - - *target_pointer++ = r1; - *target_pointer++ = g1; - *target_pointer++ = b1; - - *target_pointer++ = r2; - *target_pointer++ = g2; - *target_pointer++ = b2; - - return 0; -#endif - return 1; -} diff --git a/src/modules/linsys/consumer_sdi.yml b/src/modules/linsys/consumer_sdi.yml deleted file mode 100644 index ac26e3cc8..000000000 --- a/src/modules/linsys/consumer_sdi.yml +++ /dev/null @@ -1,12 +0,0 @@ -schema_version: 0.1 -type: consumer -identifier: sdi -title: Linear Systems SDI (*deprecated*) -version: 1 -copyright: Broadcasting Center Europe S.A. -creator: Thomas Kurpick -license: GPLv2 -language: en -tags: - - Audio - - Video diff --git a/src/modules/linsys/deprecated b/src/modules/linsys/deprecated deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/modules/linsys/factory.c b/src/modules/linsys/factory.c deleted file mode 100644 index 9519e0df8..000000000 --- a/src/modules/linsys/factory.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * factory.c for Linsys SDI consumer -*/ - -#include -#include -#include - -extern mlt_consumer consumer_SDIstream_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/linsys/%s", mlt_environment( "MLT_DATA" ), (char*) data ); - return mlt_properties_parse_yaml( file ); -} - -MLT_REPOSITORY -{ - MLT_REGISTER( consumer_type, "sdi", consumer_SDIstream_init ); - MLT_REGISTER_METADATA( consumer_type, "sdi", metadata, "consumer_sdi.yml" ); -} diff --git a/src/modules/linsys/gpl b/src/modules/linsys/gpl deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/modules/linsys/sdi_generator.c b/src/modules/linsys/sdi_generator.c deleted file mode 100644 index f48776c5c..000000000 --- a/src/modules/linsys/sdi_generator.c +++ /dev/null @@ -1,2411 +0,0 @@ -/** - * - * MLT SDI Consumer: - * request video and audio data from MLT and generate an SDI stream - * - * Copyright (C) Broadcasting Center Europe S.A. http://www.bce.lu - * an RTL Group Company http://www.rtlgroup.com - * All rights reserved. - * - * E-mail: support_plasec@bce.lu - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * - * DESCRIPTION: - * This software act as interface between the MLT Frameworkas as - * MLT Consumer and the Linear Systems Ltd. SMPTE 292M and SMPTE 259M-C boards. - * - * Linear Systems can be contacted at http://www.linsys.ca - * - ********************************************************************************** - * System : INTeL I686 64Bit - * OS : Linux SuSE Kernel 2.6.27.39-0.2-default - * Compiler: gcc 4.3.2 (c++) - ********************************************************************************** - * Project : MLT SDI Consumer for SD and HD - * Started by : Thomas Kurpick, Dipl.Inf. (FH) - ********************************************************************************** - * Supported and tested boards for SD-SDI or HD-SDI Output: - * PCI SDI Masterâ„¢ (model 107) - * PCIe SDI Masterâ„¢ (model 159) - * PCIe LP SDI Masterâ„¢ FD (model 145) - * PCIe LP SDI Masterâ„¢ Quad/o (model 180) - * PCIe LP HD-SDI Masterâ„¢ O (model 193) - * - * Note: PCIe LP HD-SDI Masterâ„¢ O (model 193) is an VidPort model and supports an - * separate video and audio interface. Device file: - * /dev/sdivideotx[] for active video data - * /dev/sdiaudiotx[] for pcm audio data - * - * This mlt consumer use the following device files: - * /dev/sditx[] (SD-PAL) up to 8 x AES (8 x stereo / 16 audio channels) - * /dev/sdivideotx[] (HD) - * /dev/sdiaudiotx[] (HD) up to 4 x AES (4 x stereo / 8 audio channels) - * - * - ********************************************************************************** - * Last modified by: - * Thomas Kurpick 08.Jan.2010 - * Ver. 2.0 - * - ********************************************************************************** - * - * Consumer properties: - * 'dev_video' - * 'dev_audio' - * 'blanking' - * Only to monitor the SDI output a beta version of jpeg-writer is implemented. - * 'jpeg_files' a number for output interval - * 'save_jpegs' path for image - * - * EXAMPLE: - * - * SDI boards with full frame stream (with blanking): - * melt video.dv -consumer sdi:/dev/sditx0 buffer=0; - * melt video.dv -consumer sdi:/dev/sditx0 buffer=0 blanking=true; - * melt video.dv -consumer sdi dev_video=/dev/sditx0 buffer=0 blanking=true; - * melt video.dv audio_index=all -consumer sdi dev_video=/dev/sditx0 buffer=0 blanking=true; - * - * SDI boards without full frame stream (without blanking): - * melt -profile atsc_1080i_50 video.mpeg audio_index=1 -consumer sdi dev_video=/dev/sdivideotx0 dev_sdiaudio=/dev/sdiaudiotx0 blanking=false - * melt -profile atsc_1080i_50 video.mpeg audio_index=all -consumer sdi dev_video=/dev/sdivideotx0 dev_sdiaudio=/dev/sdiaudiotx0 blanking=false - * melt -profile atsc_1080i_50 video.mpeg audio_index=all -consumer sdi dev_video=/dev/sdivideotx0 dev_sdiaudio=/dev/sdiaudiotx0 blanking=false jpeg_files=25 save_jpegs=channel_04.jpg - * - * - * SDI output formats and MLT profiles: - * ##################################################################################################################################################### - * ########## SMPTE 274M 1920 x 1080 Image Sample Structure ############################################################################################ - * ##################################################################################################################################################### - * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model) - * 4 1920 x 1080/60/I interlaced 30 HZ 4 x AES (8 channels) atsc_1080i_60 193 - * 5 1920 x 1080/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080i_5994 193 - * 6 1920 x 1080/50/I interlaced 25 HZ 4 x AES (8 channels) atsc_1080i_50 193 - * 7 1920 x 1080/30/P progressive 30 HZ 4 x AES (8 channels) atsc_1080p_30 193 - * 8 1920 x 1080/29.97/P progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_1080p_2997 193 - * 9 1920 x 1080/25/P progressive 25 HZ 4 x AES (8 channels) atsc_1080p_25 193 - * 10 1920 x 1080/24/P progressive 24 HZ 4 x AES (8 channels) atsc_1080p_24 193 - * 11 1920 x 1080/23.98/P progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_1080p_2398 193 - * - * ##################################################################################################################################################### - * ########## SMPTE 296M 1280 × 720 Progressive Image Sample Structure ################################################################################# - * ##################################################################################################################################################### - * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model) - * 1 1280 × 720/60 progressive 60 HZ 4 x AES (8 channels) atsc_720p_60 193 - * 2 1280 × 720/59.94 progressive 60000/1001 ~ 59.97 HZ 4 x AES (8 channels) atsc_720p_5994 193 - * 3 1280 × 720/50 progressive 50 HZ 4 x AES (8 channels) atsc_720p_50 193 - * 4 1280 × 720/30 progressive 30 HZ 4 x AES (8 channels) atsc_720p_30 193 - * 5 1280 × 720/29.97 progressive 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) atsc_720p_2997 193 - * 6 1280 × 720/25 progressive 25 HZ 4 x AES (8 channels) atsc_720p_25 193 - * 7 1280 × 720/24 progressive 24 HZ 4 x AES (8 channels) atsc_720p_24 193 - * 8 1280 × 720/23.98 progressive 24000/1001 ~ 23.98 HZ 4 x AES (8 channels) atsc_720p_2398 193 - * - * ##################################################################################################################################################### - * ########## SMPTE 125M 486i 29.97Hz & BT.656 576i 25Hz ############################################################################################### - * ##################################################################################################################################################### - * System No. System nomenclature Form of scanning Frame rate Embedded Audio MLT profile Linsys board support (model) - * SD PAL 720 × 576/50/I interlaced 25 HZ 8 x AES (16 channels) dv_pal 180,145,159,107 - * SD PAL 720 × 576/50/I interlaced 25 HZ 4 x AES (8 channels) dv_pal 193 - * SD NTSC 720 × 486/59.94/I interlaced 30000/1001 ~ 29.97 HZ 8 x AES (16 channels) sdi_486i_5994 TODO:180,145,159,107 - * SD NTSC 720 × 486/59.94/I interlaced 30000/1001 ~ 29.97 HZ 4 x AES (8 channels) sdi_486i_5994 193 - * - **/ - -#include "sdi_generator.h" - -/*!/brief initialization of the file handlers for the playout - * @param *device_video: file or SDITX device or SDIVIDEOTX device - * @param *device_audio: file or SDIAUDIOTX device - * @param blanking: true or false (if false the consumer write only active video data without any VANH or HANC) - */ -static int sdi_init(char *device_video, char *device_audio, uint8_t blanking, mlt_profile myProfile, - const struct audio_format * audio_format) { - - // set device file - device_file_video = device_video; - device_file_audio = device_audio; - - // set flag for using of blanking with ancillary data - info.blanking = blanking; - - // set pack method for SDI word conversion - pack = pack8; - //pack = pack10; - //pack = pack_v210; - - // check format - if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1 - && myProfile->progressive == 0) { - info.fmt = &FMT_1080i60; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080I_60HZ; - } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den - == 1001 && myProfile->progressive == 0) { - info.fmt = &FMT_1080i5994; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080I_59_94HZ; - } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1 - && myProfile->progressive == 0) { - info.fmt = &FMT_1080i50; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080I_50HZ; - } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1 - && myProfile->progressive == 1) { - info.fmt = &FMT_1080p30; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_30HZ; - } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den - == 1001 && myProfile->progressive == 1) { - info.fmt = &FMT_1080p2997; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_29_97HZ; - } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1 - && myProfile->progressive == 1) { - info.fmt = &FMT_1080p25; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_25HZ; - } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 24 && myProfile->frame_rate_den == 1 - && myProfile->progressive == 1) { - info.fmt = &FMT_1080p24; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_24HZ; - } else if (myProfile->width == 1920 && myProfile->height == 1080 && myProfile->frame_rate_num == 24000 && myProfile->frame_rate_den - == 1001 && myProfile->progressive == 1) { - info.fmt = &FMT_1080p2398; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_274M_1080P_23_98HZ; - } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 60 && myProfile->frame_rate_den == 1 - && myProfile->progressive == 1) { - info.fmt = &FMT_720p60; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_60HZ; - } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 60000 && myProfile->frame_rate_den - == 1001 && myProfile->progressive == 1) { - info.fmt = &FMT_720p5994; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_59_94HZ; - } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 50 && myProfile->frame_rate_den == 1 - && myProfile->progressive == 1) { - info.fmt = &FMT_720p50; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_50HZ; - } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 30 && myProfile->frame_rate_den == 1 - && myProfile->progressive == 1) { - info.fmt = &FMT_720p30; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_30HZ; - } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den - == 1001 && myProfile->progressive == 1) { - info.fmt = &FMT_720p2997; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_29_97HZ; - } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1 - && myProfile->progressive == 1) { - info.fmt = &FMT_720p25; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_25HZ; - } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 24 && myProfile->frame_rate_den == 1 - && myProfile->progressive == 1) { - info.fmt = &FMT_720p24; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_24HZ; - } else if (myProfile->width == 1280 && myProfile->height == 720 && myProfile->frame_rate_num == 24000 && myProfile->frame_rate_den - == 1001 && myProfile->progressive == 1) { - info.fmt = &FMT_720p2398; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_296M_720P_23_98HZ; - } else if (myProfile->width == 720 && myProfile->height == 576 && myProfile->frame_rate_num == 25 && myProfile->frame_rate_den == 1 - && myProfile->progressive == 0) { - info.fmt = &FMT_576i50; - sdi_frame_mode = SDIVIDEO_CTL_BT_601_576I_50HZ; - } else if (myProfile->width == 720 && myProfile->height == 486 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den - == 1001 && myProfile->progressive == 0) { - info.fmt = &FMT_486i5994; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_125M_486I_59_94HZ; - } else if (myProfile->width == 720 && myProfile->height == 480 && myProfile->frame_rate_num == 30000 && myProfile->frame_rate_den - == 1001 && myProfile->progressive == 0) { - info.fmt = &FMT_480i5994; - sdi_frame_mode = SDIVIDEO_CTL_SMPTE_125M_486I_59_94HZ; - } else { - printf("Consumer got unknown format: %s", myProfile->description); - info.fmt = &FMT_576i50; - sdi_frame_mode = SDIVIDEO_CTL_BT_601_576I_50HZ; - } - - printf("Consumer use format: %s\nProfile: %i %i %i %i %i\n", myProfile->description, myProfile->width, myProfile->height, - myProfile->frame_rate_num, myProfile->frame_rate_den, myProfile->progressive); - - // Check if the format supports own blanking (note: model 193 supports currently only active video at the video device file) - if (info.blanking && info.fmt != &FMT_576i50) { - printf("SDI consumer doesn't support blanking(HANC) for the configured SD board and SDI format. Try argument: blanking=false\n"); - return 0; - } - - // if we write our own HANC we need an AES channel status bit array - if (info.blanking) { - - // small description - // http://www.sencore.com/newsletter/Nov05/DigAudioChannelStatusBits.htm - // or - // http://www.sencore.com/uploads/files/DigAudioChannelStatusBits.pdf - - // create empty AESChannelStatusBitArray - int i = 0; - for (i = 0; i < sizeof(AESChannelStatusBitArray) / sizeof(AESChannelStatusBitArray[0]); i++) - AESChannelStatusBitArray[i] = 0; - - /** - * Professional Format - Channel Status Bits - **/ - ////// Byte 0 ////// - AESChannelStatusBitArray[0] = 1; // professional format - - AESChannelStatusBitArray[1] = 0; // PCM Format - - AESChannelStatusBitArray[2] = 1; // Emphasis: [100] No Emphasis - AESChannelStatusBitArray[3] = 0; // ^ - AESChannelStatusBitArray[4] = 0; // ^ - - AESChannelStatusBitArray[5] = 0; // locked - - AESChannelStatusBitArray[6] = 0; // sample frequency Fs: [01]48kHz, [10]44kHz, [11]32kHz - AESChannelStatusBitArray[7] = 1; // ^ - ////// Byte 1 ////// - AESChannelStatusBitArray[8] = 0; // channel mode: [0000] not indicated, [0001]2channels, [0010]1channel mono, ... - AESChannelStatusBitArray[9] = 0; // ^ - AESChannelStatusBitArray[10] = 0; // ^ - AESChannelStatusBitArray[11] = 1; // ^ - ////// Byte 2 ////// - AESChannelStatusBitArray[19] = 0; // Encoded sample word length [100]20bits, - AESChannelStatusBitArray[20] = 0; // - AESChannelStatusBitArray[21] = 0; // - ////// Byte 3 ////// - AESChannelStatusBitArray[24] = 0; // - AESChannelStatusBitArray[25] = 0; // - AESChannelStatusBitArray[26] = 0; // - AESChannelStatusBitArray[27] = 0; // - AESChannelStatusBitArray[28] = 0; // - AESChannelStatusBitArray[29] = 0; // - AESChannelStatusBitArray[30] = 0; // - AESChannelStatusBitArray[31] = 0; // Multi Channel Mode - ////// Byte 4-21 ////// - //AESChannelStatusBitArray[32-179]= 0; - ////// Byte 22 ////// - AESChannelStatusBitArray[180] = 0; // Reliability Flags - AESChannelStatusBitArray[181] = 1; // ^ - AESChannelStatusBitArray[182] = 1; // ^ - AESChannelStatusBitArray[183] = 1; // ^ - ////// Byte 23 ////// - AESChannelStatusBitArray[184] = 0; // Cyclic Redundancy Check - AESChannelStatusBitArray[185] = 1; // ^ - AESChannelStatusBitArray[186] = 0; // ^ - AESChannelStatusBitArray[187] = 0; // ^ - AESChannelStatusBitArray[188] = 1; // ^ - AESChannelStatusBitArray[189] = 0; // ^ - AESChannelStatusBitArray[190] = 1; // ^ - AESChannelStatusBitArray[191] = 1; // ^ - } - - // set buffer for one line of active video samples - line_buffer = (uint16_t*) calloc(info.fmt->samples_per_line, sizeof(uint16_t)); - - // calculate and set buffer for the complete SDI frame - if (info.fmt != &FMT_576i50 && info.fmt != &FMT_486i5994) { - if (info.blanking) { - if (pack == pack_v210) { - samples = (info.fmt->samples_per_line / 96 * 48) + ((info.fmt->samples_per_line % 96) ? 48 : 0); - sdi_frame_size = samples * info.fmt->lines_per_frame * 8 / 3; - } else { - sdi_frame_size = info.fmt->samples_per_line * info.fmt->lines_per_frame; - } - } else { - if (pack == pack_v210) { - samples = (info.fmt->active_samples_per_line / 96 * 48) + ((info.fmt->active_samples_per_line % 96) ? 48 : 0); - sdi_frame_size = samples * info.fmt->active_lines_per_frame * 8 / 3; - } else { - sdi_frame_size = info.fmt->active_samples_per_line * info.fmt->active_lines_per_frame; - } - } - } else { - if (info.blanking) { - if (pack == pack_v210) { - sdi_frame_size = info.fmt->samples_per_line * 4 / 3 * info.fmt->lines_per_frame; - } else if (pack == pack8) { - sdi_frame_size = info.fmt->samples_per_line * info.fmt->lines_per_frame; - } else { - sdi_frame_size = info.fmt->samples_per_line * 10 / 8 * info.fmt->lines_per_frame; - } - } else { - if (pack == pack_v210) { - sdi_frame_size = info.fmt->active_samples_per_line * 4 / 3 * info.fmt->active_lines_per_frame; - } else if (pack == pack8) { - sdi_frame_size = info.fmt->active_samples_per_line * info.fmt->active_lines_per_frame; - } else { - sdi_frame_size = info.fmt->active_samples_per_line * 10 / 8 * info.fmt->active_lines_per_frame; - } - } - } - - // (*10/8 because we store (TOTAL_SAMPLES*TOTAL_LINES) words with 10 bit in this 8 bit array) ) - if (info.fmt == &FMT_576i50 && info.blanking) { - sdi_frame_size = info.fmt->samples_per_line * 10 / 8 * info.fmt->lines_per_frame; - } - - if (info.blanking) { - printf("SDI frame size: %"PRIu64"\n", sdi_frame_size); - } else { - printf("Frame size for active video: %"PRIu64"\n", sdi_frame_size); - } - - /** - * Setup HD-SDI Master device (vidport): - * - * if device_file_video available then - * if vidport available - * 1. setup - * end - * 1. open device file handler - * - * if device_file_audio available then - * 1. setup - * 2. open device file handler - * end - * end - **/ - if (device_file_video != NULL) { - - // If we use a Linsys HD board with active video (without blanking) setup the board for the used mode - if (strstr(device_file_video, "sdivideotx") != NULL && !info.blanking) { - - char * value; - - // Buffer size - value = itoa(sdi_frame_size); - setSDIVideoProperties(SETTING_BUFFER_SIZE_VIDEO, value, device_video); - free(value); - - // Frame Mode - value = itoa(sdi_frame_mode); - setSDIVideoProperties(SETTING_FRAME_MODE, value, device_video); - free(value); - - // Data Mode - if (pack == pack8) - setSDIVideoProperties(SETTING_DATA_MODE, "0", device_video); - else if (pack == pack_v210) - setSDIVideoProperties(SETTING_DATA_MODE, "1", device_video); - } - - // open file handle for SDI(video) output - if ((fh_sdi_video = open(device_file_video, O_WRONLY)) == -1) { - perror(NULL); - printf("\ncould not open video output destination: %s\n", device_file_video); - return 0; - } - printf("SDI consumer uses video device file: %s\n", device_file_video); - - // Check if we have to use a separate device file for audio - if (device_file_audio != NULL) { - - // set settings for audio device file - if (strstr(device_file_audio, "sdiaudiotx") != NULL && !info.blanking) { - - char * value; - - /** - * prepare sample size - * MLT supports: 16bit, 32bit - * LINSYS SDI boards supports: 16bit, 24bit, 32bit - * we set 16bit as default - **/ - uint8_t sample_size = audio_format->aformat == mlt_audio_s32 ? 32 : 16; - - // Buffer size - // audio buffer per frame (Bytes) = sample rate / frame rate * ( sample size / 1Byte ) x channels - value = itoa( - (uint64_t) audio_format->sample_rate / ( (uint64_t) myProfile->frame_rate_num / (uint64_t) myProfile->frame_rate_den) * (uint64_t) sample_size / 8 - * (uint64_t) audio_format->channels); - setSDIAudioProperties(SETTING_BUFFER_SIZE_AUDIO, value, device_audio); - free(value); - - // channels - value = itoa(audio_format->channels); - setSDIAudioProperties(SETTING_CHANNELS, value, device_audio); - free(value); - - // sample rate - value = itoa(audio_format->sample_rate); - setSDIAudioProperties(SETTING_SAMPEL_RATE, value, device_audio); - free(value); - - // sample size - value = itoa(sample_size); - setSDIAudioProperties(SETTING_SAMPLE_SIZE, value, device_audio); - free(value); - } - - // open file handle for audio output - if ((fh_sdi_audio = open(device_file_audio, O_WRONLY)) == -1) { - perror(NULL); - printf("\nCould not open audio output destination: %s\n", device_file_audio); - return 0; - } - printf("SDI consumer uses audio device file: %s\n", device_file_audio); - } - - } - - // set buffer for the complete SDI frame - data = (uint8_t*) calloc(sdi_frame_size, sizeof(uint8_t)); - - return 1; -} - -/** - * Writes video and audio to specified files in SDI format - * @param *vBuffer: Pointer to a video Buffer - * @param aBuffer[][] - * @param *audio_format: mlt audio_format - * @param audio_streams: number of audio streams which have content in aBuffer (available 0-8) - * @return current DBN (data block number of SDI frame) - **/ -static int sdi_playout(uint8_t *vBuffer, int16_t aBuffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], const struct audio_format * audio_format, - int audio_streams, int my_DBN) { - - // Pointer to the start of data. This is used to fill data line by line - uint8_t *p = data; - - //******************************************************************************************* - //**************** Build the SDI frame line by line **************************************** - //******************************************************************************************* - - /* - * if SDI FMT_576i50 for card ASSY 145 or ASSY 159, with access to whole SDI frame buffer - * and device_file_audio must be NULL - * than we write own audio data, - * else - * than HD for card ASSY 193 - */ - //if (info.fmt == &FMT_576i50 && device_file_audio == NULL && !strcmp(device_file_video, "/dev/sdivideotx0")) { - if (info.fmt == &FMT_576i50 && info.blanking) { - - //counter for the lines - int i = 0; - int16_t AudioGroupCounter = 0; - - /*#####################################################*/ - /*######## FIELD 1 #######################*/ - /*#####################################################*/ - - info.xyz = &FIELD_1_VERT_BLANKING; - - // line 1-22 VERTICAL_BLANKING:23 lines SAV 0x2ac EAV 0x2d8 - for (i = 1; i <= 5; i++) { - create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - } - for (i = 6; i <= 8; i++) { - create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - } - for (i = 9; i <= 22; i++) { - create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - } - // line 23-310 ACTIVE: 287 lines SAV 0x200 EAV 0x274 - info.xyz = &FIELD_1_ACTIVE; - int f1counter = 1; // only odd lines - for (i = 23; i <= 310; i++) { - create_SD_SDI_Line(line_buffer, &info, FIELD_1, ACTIVE_VIDEO, vBuffer, aBuffer, i, f1counter, getDBN(my_DBN++), - AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - f1counter += 2; - } - i = 311; - // line 311-312 VERTICAL_BLANKING: 2 lines SAV 0x2ac EAV 0x2d8 - info.xyz = &FIELD_1_VERT_BLANKING; - create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i++); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - create_SD_SDI_Line(line_buffer, &info, FIELD_1, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i++); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - - /*#####################################################*/ - /*######## FIELD 2 ########################*/ - /*#####################################################*/ - - info.xyz = &FIELD_2_VERT_BLANKING; - - // line 313-336 VERTICAL_BLANKING: 23 lines SAV 0x3b0 EAV 0x3c4 - create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i++); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - - create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i++); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - - create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i++); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - - create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i++); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - - create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i++); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - - create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i++); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - - // `getAudioGroups2Write()`=0 - for (i = 319; i <= 321; i++) { - create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - } - for (i = 322; i <= 335; i++) { - create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - } - // line 336-623 ACTIVE: 288 lines SAV 0x31c EAV 0x368 - info.xyz = &FIELD_2_ACTIVE; - int f2counter = 2; // only even Lines - for (i = 336; i <= 623; i++) { - - create_SD_SDI_Line(line_buffer, &info, FIELD_2, ACTIVE_VIDEO, vBuffer, aBuffer, i, f2counter, getDBN(my_DBN++), - AudioGroupCounter, getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - f2counter += 2; - } - // line 624-625 VERTICAL_BLANKING: 2 lines SAV 0x3b0 EAV 0x3c4 - info.xyz = &FIELD_2_VERT_BLANKING; - for (i = 624; i <= 625; i++) { - create_SD_SDI_Line(line_buffer, &info, FIELD_2, VERT_BLANKING, vBuffer, aBuffer, i, 0, getDBN(my_DBN++), AudioGroupCounter, - getNumberOfAudioGroups2Write(i), audio_streams); - AudioGroupCounter += getNumberOfAudioGroups2Write(i); - p = pack10(p, line_buffer, info.fmt->samples_per_line); - } - - } else { // use HD board without blanking - - // start with first even line - active_video_line = 1; - - /* ***************************************** - * *********** LINE DISTRIBUTION *********** - * ***************************************** - * - * << decide form of scanning (interlaced || progressive) >> - * if (interlaced) - * << decide lines per frame (1125 || 625 || 525) >> - * if(1125) 1080x1920 HD - * than create lines - * else if(625) 576x720 PAL - * than create lines - * else (525) 486x720 NTSC - * than create lines - * else (progressive) - * << decide resolution (1125 || 750) >> - * if(1125) 1080x1920 HD - * than create lines - * else(750) 720x1280 HD - * than create lines - * - **/ - - // Generate a frame - if (info.fmt->interlaced) { - - /**************************************** - * INTERLACED - ****************************************/ - - if (info.fmt->lines_per_frame == 1125) { - - if (info.blanking) { - elements = info.fmt->samples_per_line; - info.xyz = &FIELD_1_VERT_BLANKING; - for (info.ln = 1; info.ln <= 20; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - } else { - elements = info.fmt->active_samples_per_line; - } - info.xyz = &FIELD_1_ACTIVE; - for (info.ln = 21; info.ln <= 560; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); - p = pack(p, line_buffer, elements); - active_video_line += 2; - } - if (info.blanking) { - info.xyz = &FIELD_1_VERT_BLANKING; - for (info.ln = 561; info.ln <= 563; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - info.xyz = &FIELD_2_VERT_BLANKING; - for (info.ln = 564; info.ln <= 583; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - } - // start with first odd line - active_video_line = 2; - - info.xyz = &FIELD_2_ACTIVE; - for (info.ln = 584; info.ln <= 1123; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); - p = pack(p, line_buffer, elements); - active_video_line += 2; - } - if (info.blanking) { - info.xyz = &FIELD_2_VERT_BLANKING; - for (info.ln = 1124; info.ln <= 1125; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - } - } else if (info.fmt->lines_per_frame == 625) { - - elements = info.fmt->active_samples_per_line; - - // start with first even line - active_video_line = 1; - - /** - * Generate an SDI PAL frame - **/ - if (info.blanking) { - info.xyz = &FIELD_1_VERT_BLANKING; - for (info.ln = 1; info.ln <= 22; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - } - info.xyz = &FIELD_1_ACTIVE; - for (info.ln = 23; info.ln <= 310; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); - p = pack(p, line_buffer, elements); - active_video_line += 2; - } - if (info.blanking) { - info.xyz = &FIELD_1_VERT_BLANKING; - for (info.ln = 311; info.ln <= 312; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - info.xyz = &FIELD_2_VERT_BLANKING; - for (info.ln = 313; info.ln <= 335; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - } - - // start with first odd line - active_video_line = 2; - - info.xyz = &FIELD_2_ACTIVE; - for (info.ln = 336; info.ln <= 623; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); - p = pack(p, line_buffer, elements); - active_video_line += 2; - } - if (info.blanking) { - info.xyz = &FIELD_2_VERT_BLANKING; - for (info.ln = 624; info.ln <= 625; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - } - } else if (info.fmt->lines_per_frame == 525) { - - /** - * Generate an SDI NTSC frame - * - * - * 16 lines VERT_BLANKING FIELD_1_VERT_BLANKING - * 1 lines VERT_BLANKING FIELD_1_ACTIVE - * 3 lines ACTIVE_VIDEO FIELD_1_ACTIVE (opt. video data) - * 240 lines ACTIVE_VIDEO FIELD_1_ACTIVE - * 2 lines VERT_BLANKING FIELD_1_VERT_BLANKING - * - * 8 lines VERT_BLANKING FIELD_2_VERT_BLANKING - * 9 lines VERT_BLANKING FIELD_2_VERT_BLANKING - * 3 lines ACTIVE_VIDEO FIELD_2_ACTIVE (opt. video data) - * 240 lines ACTIVE_VIDEO FIELD_2_ACTIVE - * 4 lines VERT_BLANKING FIELD_2_VERT_BLANKING - * - **/ - - elements = info.fmt->active_samples_per_line; - - active_video_line = 1; - - if (info.blanking) { - info.xyz = &FIELD_1_VERT_BLANKING; - for (info.ln = 1; info.ln <= 15; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - for (info.ln = 16; info.ln <= 16; info.ln++) { - info.xyz = &FIELD_1_ACTIVE; - mkline(line_buffer, &info, VERT_BLANKING); - p = pack(p, line_buffer, elements); - } - } - - info.xyz = &FIELD_1_ACTIVE; - - // 480 or 486 lines - if (info.fmt == &FMT_480i5994) { - // 3 lines opt. video data - for (info.ln = 17; info.ln <= 19; info.ln++) { - mkline(line_buffer, &info, BLACK); - p = pack(p, line_buffer, elements); - } - // 240 lines - for (info.ln = 20; info.ln <= 259; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); - p = pack(p, line_buffer, elements); - active_video_line += 2; - } - } else { - // 243 lines - for (info.ln = 17; info.ln <= 259; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); - p = pack(p, line_buffer, elements); - active_video_line += 2; - } - } - if (info.blanking) { - // 2 lines vertical data - info.xyz = &FIELD_1_VERT_BLANKING; - for (info.ln = 260; info.ln <= 261; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - // 8 lines vertical data - info.xyz = &FIELD_2_VERT_BLANKING; - for (info.ln = 262; info.ln <= 269; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - // 9 lines - for (info.ln = 270; info.ln <= 278; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - - } - - active_video_line = 0; - - // 480 or 486 lines - if (info.fmt == &FMT_480i5994) { - // 3 lines opt. video data - info.xyz = &FIELD_2_ACTIVE; - for (info.ln = 279; info.ln <= 281; info.ln++) { - mkline(line_buffer, &info, BLACK); - p = pack(p, line_buffer, elements); - } - // 240 lines - for (info.ln = 282; info.ln <= 521; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); - p = pack(p, line_buffer, elements); - active_video_line += 2; - } - } else { - // 243 lines - for (info.ln = 279; info.ln <= 521; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, active_video_line, ACTIVE_VIDEO, vBuffer); - p = pack(p, line_buffer, elements); - active_video_line += 2; - } - } - // 4 lines vertical data - if (info.blanking) { - info.xyz = &FIELD_2_VERT_BLANKING; - for (info.ln = 522; info.ln <= 525; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - } - } - } else { - - /**************************************** - * PROGRESSIVE - ****************************************/ - - // start with first line numerber - active_video_line = 0; - - if (info.fmt->lines_per_frame == 1125) { - if (info.blanking) { - elements = info.fmt->samples_per_line; - info.xyz = &FIELD_1_VERT_BLANKING; - for (info.ln = 1; info.ln <= 41; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - } else { - elements = info.fmt->active_samples_per_line; - } - info.xyz = &FIELD_1_ACTIVE; - for (info.ln = 42; info.ln <= 1121; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, active_video_line++, ACTIVE_VIDEO, vBuffer); - p = pack(p, line_buffer, elements); - } - if (info.blanking) { - info.xyz = &FIELD_1_VERT_BLANKING; - for (info.ln = 1122; info.ln <= 1125; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - } - } else { - if (info.blanking) { - elements = info.fmt->samples_per_line; - info.xyz = &FIELD_1_VERT_BLANKING; - for (info.ln = 1; info.ln <= 25; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - } else { - elements = info.fmt->active_samples_per_line; - } - info.xyz = &FIELD_1_ACTIVE; - for (info.ln = 26; info.ln <= 745; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, active_video_line++, ACTIVE_VIDEO, vBuffer); - p = pack(p, line_buffer, elements); - } - if (info.blanking) { - info.xyz = &FIELD_1_VERT_BLANKING; - for (info.ln = 746; info.ln <= 750; info.ln++) { - create_HD_SDI_Line(line_buffer, &info, 0, VERT_BLANKING, vBuffer); - p = pack(p, line_buffer, elements); - } - } - } - } - } - - // sum of bytes that have already been written to file - int bytes = 0; - // store actual written bytes per 'write() - int written_bytes = 0; - - /** - * WRITE BUFFER TO FILEHANDLE - **/ - // Write the complete frame to output - // The "while" is necessary because the sdi device file does not take the complete frame at once - written_bytes = 0; - while (bytes < sdi_frame_size) { - - if ((written_bytes = write(fh_sdi_video, data + bytes, sdi_frame_size - bytes)) < 0) { - fprintf(stderr, "\nunable to write SDI video.\n"); - return -1; - } - bytes += written_bytes; - } - - // Check for events of the SDI board - unsigned int val; - if (ioctl(fh_sdi_video, SDI_IOC_TXGETEVENTS, &val) < 0) { - // Maybe this is not an SDI device... - //fprintf(stderr, "SDI VIDEO output:"); - //perror("unable to get the transmitter event flags"); - } else if (val) { - if (val & SDI_EVENT_TX_BUFFER) { - printf("SDI VIDEO driver transmit buffer queue underrun " - "detected.\n"); - fflush(stdout); - } - if (val & SDI_EVENT_TX_FIFO) { - printf("SDI VIDEO onboard transmit FIFO underrun detected.\n"); - fflush(stdout); - } - if (val & SDI_EVENT_TX_DATA) { - printf("SDI VIDEO transmit data change detected.\n"); - fflush(stdout); - } - } - - // if available write audio data - if (fh_sdi_audio) { - - // count written bytes - written_bytes = 0; - - // set number of samples and cut by 1600 if NTSC (handle problem of real time encoding of NTSC frequencies) - size_t samples_total_per_track = audio_format->samples; - uint16_t sample_number = 0; - size_t channels_per_track_total = 2; - uint8_t stream_number = 0; - - //printf("samples_total_per_track:%li\n", samples_total_per_track); - - // to write blockwise 2 samples of one track we must calculate the number of bytes we want to write per write-session - // 2samples = 2x16Bit = 32Bit = 4Byte - // 2samples = 2x32Bit = 64Bit = 8Byte - // set total bytes per session - size_t bytes_total = 0; - bytes_total = audio_format->aformat == mlt_audio_s16 ? channels_per_track_total * sizeof(int16_t) : bytes_total; - bytes_total = audio_format->aformat == mlt_audio_s32 ? channels_per_track_total * sizeof(int32_t) : bytes_total; - - // write all samples of all streams interleaved - /** - * aBuffer[track0]+sample1 - * aBuffer[track0]+sample2 - * aBuffer[track1]+sample1 - * aBuffer[track1]+sample2 - * aBuffer[track.]+sample1 - * aBuffer[track.]+sample2 - * - * aBuffer[track0]+sample3 - * aBuffer[track0]+sample4 - * aBuffer[track1]+sample3 - * aBuffer[track1]+sample4 - * aBuffer[track.]+sample3 - * aBuffer[track.]+sample4 - * - * aBuffer[track0]+sample5 - * aBuffer[track0]+sample6 - * aBuffer[track1]+sample5 - * aBuffer[track1]+sample6 - * aBuffer[track.]+sample5 - * aBuffer[track.]+sample6 - **/ - int sum_written_bytes = 0; - int sum_written_bytes_a = 0; - int sum_written_bytes_b = 0; - - // write all samples per track - while (sample_number < samples_total_per_track) { - - stream_number = 0; - - /** - * Because we have and write a fix number of audio streams to SDI board: - * we have a actual number of real audio tracks and a rest number of pseudo tracks - **/ - // write all streams - while (stream_number < audio_streams) { - - // write for every stream n samples - // n = number of channels per stream - written_bytes = 0; - while (written_bytes < bytes_total) { - written_bytes += write(fh_sdi_audio, (uint8_t *) aBuffer[stream_number] + sample_number * bytes_total + written_bytes, - bytes_total - written_bytes); - } - sum_written_bytes += written_bytes; - sum_written_bytes_a += written_bytes; - - stream_number++; - } - - // write pseudo tracks - // now fill rest of audio tracks(AES frames) with NULL or copy of first track - while (stream_number < audio_format->channels / 2) { - - // write for every stream n samples - // n = number of channels per stream - written_bytes = 0; - while (written_bytes < bytes_total) { - written_bytes += write(fh_sdi_audio, (uint8_t *) aBuffer[0] + sample_number * bytes_total + written_bytes, - bytes_total - written_bytes); - } - sum_written_bytes += written_bytes; - sum_written_bytes_b += written_bytes; - - stream_number++; - } - - sample_number++; - - // Check for events of the SDI audio device - unsigned int val; - if (ioctl(fh_sdi_audio, SDIAUDIO_IOC_TXGETEVENTS, &val) < 0) { - //Maybe this is not an SDI device... - // fprintf(stderr, "SDI AUDIO output:"); - // perror("unable to get the transmitter event flags"); - } else if (val) { - if (val & SDIAUDIO_EVENT_TX_BUFFER) { - printf("SDI AUDIO driver transmit buffer queue underrun " - "detected.\n"); - } - if (val & SDIAUDIO_EVENT_TX_FIFO) { - printf("SDI AUDIO onboard transmit FIFO underrun detected.\n"); - } - if (val & SDIAUDIO_EVENT_TX_DATA) { - printf("SDI AUDIO transmit data change detected.\n"); - } - } - } - } - - return getDBN(my_DBN); -} // end sdimaster_playout() - - -//**************************************************************************************** -//*************************** Create Line ********************************************** -//**************************************************************************************** - -/** generate one SDI line - * @param *buf: buffer to hold the line - * @param field: size of the video Buffer - * @param active: v-blank or active-video - * @param *video_buffer: video buffer - * @param *audio_buffer2: 1.audio buffer ch1-ch2 - * @param *audio_buffer1: 2.audio buffer ch2-ch3 - * @param line: linenumber - * @param AudioGroupCounter: count written AudioGroup - * @param AudioGroups2Write: number of samples to write - * @param audio_streams: number of audio streams to integrate - */ -static inline int create_SD_SDI_Line(uint16_t *buf, const struct line_info *info, int field, int active, uint8_t *video_buffer, - int16_t audio_buffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], int linenumber_sdiframe, int active_video_line, int my_DBN, - int16_t AudioGroupCounter, int16_t AudioGroups2Write, int audio_streams) { - - // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2) - // ************************************************************************* - // 625 lines: | EAV | ANC | SAV | [CbY1CrY2] | - // ************************************************************************* - // 1728 SDI-words: | 4 | 280 | 4 | 720+360+360=1440 | - // ************************************************************************* - - // points to current position in line - uint16_t *p = buf; - - //######################################################################################### - /* TRS Timing Reference Signal for EAV - * [3ff] - * [000] - * [000] - * [XYZ-Wort] - * */ - - *p++ = 0x3ff; - *p++ = 0x000; - *p++ = 0x000; - *p++ = info->xyz->eav; - //######################################################################################### - - /* ANC Ancillary Data with AES - * - * [ADF][ADF][ADF][DID][DBN][DC][UDW]...[UDW][CS] - * - * */ - // write ANC Data and get number of samples are written - // step with `p` += to the number of written samples - - //printf("audio_streams:%i\n",audio_streams); - - // 1 stream, Audio Group 1 with AES Frame 1 - 2 - if (audio_streams == 1) { - p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[0], AudioGroupCounter, AudioGroups2Write); - } - // 2 streams, Audio Group 1 with AES Frame 1 - 2 - if (audio_streams == 2) { - p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); - } - // 3 streams, Audio Group 2 with AES Frame 1 - 4 - if (audio_streams == 3) { - p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); - p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[2], AudioGroupCounter, AudioGroups2Write); - } - // 4 streams, Audio Group 2 with AES Frame 1 - 4 - if (audio_streams == 4) { - p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); - p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write); - } - // 5 streams, Audio Group 3 with AES Frame 1 - 6 - if (audio_streams == 5) { - p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); - p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write); - p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[4], AudioGroupCounter, AudioGroups2Write); - } - // 6 streams, Audio Group 3 with AES Frame 1 - 6 - if (audio_streams == 6) { - p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); - p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write); - p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write); - } - // 7 streams, Audio Group 4 with AES Frame 1 - 7 - if (audio_streams == 7) { - p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); - p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write); - p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write); - p += writeANC(p, linenumber_sdiframe, 0x2F9, my_DBN, audio_buffer[6], audio_buffer[6], AudioGroupCounter, AudioGroups2Write); - } - // 8 streams, Audio Group 4 with AES Frame 1 - 7 - if (audio_streams == 8) { - p += writeANC(p, linenumber_sdiframe, 0x2FF, my_DBN, audio_buffer[0], audio_buffer[1], AudioGroupCounter, AudioGroups2Write); - p += writeANC(p, linenumber_sdiframe, 0x1FD, my_DBN, audio_buffer[2], audio_buffer[3], AudioGroupCounter, AudioGroups2Write); - p += writeANC(p, linenumber_sdiframe, 0x1FB, my_DBN, audio_buffer[4], audio_buffer[5], AudioGroupCounter, AudioGroups2Write); - p += writeANC(p, linenumber_sdiframe, 0x2F9, my_DBN, audio_buffer[6], audio_buffer[7], AudioGroupCounter, AudioGroups2Write); - } - - // Fill ANC data in until the end (position(p) to `ANCILLARY_DATA_SAMPLES`) - while (p < (buf + ANCILLARY_DATA_SAMPLES + 4)) { - // video color: black - *p++ = 0x200; - *p++ = 0x040; - } - //######################################################################################### - // TRS Timing Reference Signal for SAV - *p++ = 0x3ff; - *p++ = 0x000; - *p++ = 0x000; - *p++ = info->xyz->sav; - //######################################################################################### - - - // Because we skip the first line of video, it can happen that we read too far in the buffer - if (active_video_line >= info->fmt->active_lines_per_frame) { - active_video_line = info->fmt->active_lines_per_frame - 1; // in SD PAL was set 575 - } - //Index of the start of the current line in the video_buffer - int start_of_current_line = active_video_line * info->fmt->active_samples_per_line; - - // If VBlank then fill the line with 0x200 and 0x040 (total black) - switch (active) { - default: - case VERT_BLANKING: - while (p < (buf + info->fmt->samples_per_line)) { - *p++ = 0x200; - *p++ = 0x040; - } - break; - case ACTIVE_VIDEO: - - // Insert the video into the line - while (p < (buf + info->fmt->samples_per_line)) { // fill the rest of the line with active video - - // shift "<< 2" because 8 bit data in 10 bit word - - *p = video_buffer[start_of_current_line + ((p - 288) - buf) + 1] << 2; // Cb - p++; - if (*(p - 1) < 0x040) - *(p - 1) = 0x040; // check values - if (*(p - 1) > 0x3c0) - *(p - 1) = 0x3c0; - *p = video_buffer[start_of_current_line + ((p - 288) - buf) - 1] << 2; // Y1 - p++; - if (*(p - 1) < 0x040) - *(p - 1) = 0x040; - if (*(p - 1) > 0x3ac) - *(p - 1) = 0x3ac; - *p = video_buffer[start_of_current_line + ((p - 288) - buf) + 1] << 2; // Cr - p++; - if (*(p - 1) < 0x040) - *(p - 1) = 0x040; - if (*(p - 1) > 0x3c0) - *(p - 1) = 0x3c0; - *p = video_buffer[start_of_current_line + ((p - 288) - buf) - 1] << 2; // Y2 - p++; - if (*(p - 1) < 0x040) - *(p - 1) = 0x040; - if (*(p - 1) > 0x3ac) - *(p - 1) = 0x3ac; - - } - break; - } - return 0; -} - -/** - * create_HD_SDI_Line - generate one line - * @buf: pointer to a buffer - * @info: pointer to a line information structure - * @active_video_line - * @active: - * @video_buffer: pattern - * - * Returns a negative error code on failure and zero on success. - **/ -static inline int create_HD_SDI_Line(uint16_t *buf, const struct line_info *info, uint16_t active_video_line, unsigned int active, - uint8_t *video_buffer) { - uint16_t *p = buf, ln; - uint16_t samples = info->blanking ? info->fmt->samples_per_line : info->fmt->active_samples_per_line; - - if (active_video_line >= info->fmt->active_lines_per_frame) { - active_video_line = info->fmt->active_lines_per_frame - 1; - } - - int start_of_current_line = active_video_line * info->fmt->active_samples_per_line; - - if (info->blanking) { - - // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2) - // Example SD PAL: - // ************************************************************************* - // 625 lines: | EAV | ANC | SAV | [CbY1CrY2] | - // ************************************************************************* - // 1728 SDI-words: | 4 | 280 | 4 | 720+360+360=1440 | - // ************************************************************************* - - // write line with TRS(EAV) ANC(audio) TRS(SAV) activeVideo(CbY1CrY2) - // Example HD 1080i: - // ************************************************************************* - // 1125 lines: | EAV | LN | CRC | ANC | SAV | [CbY1CrY2] | - // ************************************************************************* - // 5280 SDI-words: | 6 | 4 | 4 | 280 | 6 | 1920+720+720=3840 | - // ************************************************************************* - - if (info->fmt == &FMT_576i50) { - /* EAV */ - *p++ = 0x3ff; - *p++ = 0x000; - *p++ = 0x000; - *p++ = info->xyz->eav; - } else { - /* EAV */ - *p++ = 1023; - *p++ = 1023; - *p++ = 0; - *p++ = 0; - *p++ = 0; - *p++ = 0; - *p++ = info->xyz->eav; - *p++ = info->xyz->eav; - /* LN */ - ln = ((info->ln & 0x07f) << 2) | (~info->ln & 0x040) << 3; - *p++ = ln; - *p++ = ln; - ln = ((info->ln & 0x780) >> 5) | 0x200; - *p++ = ln; - *p++ = ln; - /* CRC, added by serializer */ - *p++ = 512; - *p++ = 64; - *p++ = 512; - *p++ = 64; - - } - - /* Horizontal blanking */ - while (p < (buf + info->fmt->samples_per_line - info->fmt->active_samples_per_line - 4)) { - *p++ = 512; - *p++ = 64; - *p++ = 512; - *p++ = 64; - } - - if (info->fmt == &FMT_576i50) { - /* SAV */ - *p++ = 0x3ff; - *p++ = 0x000; - *p++ = 0x000; - *p++ = info->xyz->sav; - } else { - /* SAV */ - *p++ = 1023; - *p++ = 1023; - *p++ = 0; - *p++ = 0; - *p++ = 0; - *p++ = 0; - *p++ = info->xyz->sav; - *p++ = info->xyz->sav; - } - } - - switch (active) { - default: - case VERT_BLANKING: - while (p < (buf + samples)) { - *p++ = 512; - *p++ = 64; - *p++ = 512; - *p++ = 64; - } - break; - case ACTIVE_VIDEO: - - { - - while (p < (buf + samples)) { - - *p = video_buffer[start_of_current_line + (p - buf) + 1] << 2; // Cb - p++; - //check values, this needs a lot of resources - // if (*(p - 1) < 0x040) - // *(p - 1) = 0x040; - // if (*(p - 1) > 0x3c0) - // *(p - 1) = 0x3c0; - // - *p = video_buffer[start_of_current_line + (p - buf) - 1] << 2; // Y1 - p++; - // if (*(p - 1) < 0x040) - // *(p - 1) = 0x040; - // if (*(p - 1) > 0x3ac) - // *(p - 1) = 0x3ac; - // - *p = video_buffer[start_of_current_line + (p - buf) + 1] << 2; // Cr - p++; - // if (*(p - 1) < 0x040) - // *(p - 1) = 0x040; - // if (*(p - 1) > 0x3c0) - // *(p - 1) = 0x3c0; - // - *p = video_buffer[start_of_current_line + (p - buf) - 1] << 2; // Y2 - p++; - // if (*(p - 1) < 0x040) - // *(p - 1) = 0x040; - // if (*(p - 1) > 0x3ac) - // *(p - 1) = 0x3ac; - } - } - break; - } - return 0; -} - -static int writeANC(uint16_t *p, int videoline_sdiframe, uint16_t DID, int my_DBN, int16_t *audio_buffer_A, int16_t *audio_buffer_B, - int16_t AudioGroupCounter, int16_t AudioGroups2Write) { - - /** - * ANC Ancillary Data (vgl. SMPTE 291-M page 6 ) - * [ADF][ADF][ADF][DID][DBN][DC][UDW]...[UDW][CS] - * - **/ - - // save only current position for return value - uint16_t *pp = p; - // 16bit buffer to write temporarily 10bit word - uint16_t buffer = 0; // set all explicit to zero, special the bit9 for parity - // parity_counter - int8_t parity_counter = 0; - - if (AudioGroups2Write > 0) { - - // 3 ADF (Ancillary Data Flag) - *p++ = 0x000; - *p++ = 0x3FF; - *p++ = 0x3FF; - - // 1 DID (Data Identification) - // save DID for checker() - uint16_t *DID_pointer = p; - *p++ = DID;// (AES Audio Data, Group - // *p++ = 0x2FF; // (AES Audio Data, Group1=0x2FF) - // *p++ = 0x1FD; // (AES Audio Data, Group2=0x1FD) - // *p++ = 0x1FB; // (AES Audio Data, Group3=0x1FB) - // *p++ = 0x2F9; // (AES Audio Data, Group4=0x2F9) - - // 1 DBN (Data Block Number) inactiv: 1000000000 b9,b8,b7-b0 ; SMPTE 272-M chapter15.1 - // *p++ = 0x200; - - // 1 DBN (dynamic version0.1-beta ), should start with previous DBN of SDI-Frame - // -need "previous DBN" or "current framenumber" - // SDI-LINE: DBN: - // [1] [1] << start sdi frame - // [2] [2] - // [.] [.] - // [255] [255] - // [256] [1] - // [257] [2] - // [.] [.] - // [510] [255] - // [511] [1] - // [512] [2] - // [.] [.] - // [625] [115] << end sdi frame - // [1] [116] << start sdi frame - // Accuracy of videoline_sdiframe(1 up to 625) to 8bit (1-255) - //buffer = ((videoline_sdiframe-1) % 255)+1; - buffer = my_DBN; - parity_counter = 0; - // count binary ones for parity - int i = 0; - for (i = 0; i < 8; i++) { - if (buffer & (1 << i)) - parity_counter++; - } - if ((parity_counter % 2) == 0) { //else leave the 0 - buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8 - } else { - buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8 - } - *p++ = buffer; - - // 1 DC (Data Counter) - // number of UDW = AudioGroups2Write x 2AESFrames x 2channesl x 3words(X,X+1,X+2) - buffer = AudioGroups2Write * 2 * 2 * 3; - parity_counter = 0; - // count binary ones for parity - for (i = 0; i < 8; i++) { - if (buffer & (1 << i)) - parity_counter++; - } - if ((parity_counter % 2) == 0) { //else leave the 0 - buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8 - } else { - buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8 - } - *p++ = buffer; - - int16_t sample_number = 0; - int16_t counter = 0; - // write subframes: - // = n x 1 AudioGroup - // = n x 2 x 1AESFrame - // = n x 2 x 2samples - // = 4 samples - // = 4 x 3words - while (counter < AudioGroups2Write * 2) { /* 4:3 */ - - // write one Audio Group with 4 x AES subframes - // ( samples for ch01,ch02,ch03,ch04 or ch05,ch06,ch07,ch08 or ch09,ch10,ch11,ch12 or ch13,ch14,ch15,ch16) - // and use audio_buffer_A(stereo) and audio_buffer_B(stereo) - // `pack_AES_subframe()` write 3 ANC words (3*10bit), also 1 sample - - sample_number = (AudioGroupCounter * 2) + counter; - pack_AES_subframe(p, getChannelStatusBit(sample_number / 2, 1), getZBit(sample_number / 2), 0, &audio_buffer_A[sample_number]); // left - p += 3; // step 3 words - - sample_number = (AudioGroupCounter * 2) + counter + 1; - pack_AES_subframe(p, getChannelStatusBit(sample_number / 2, 2), getZBit(sample_number / 2), 1, &audio_buffer_A[sample_number]); // right - p += 3; - - sample_number = (AudioGroupCounter * 2) + counter; - pack_AES_subframe(p, getChannelStatusBit(sample_number / 2, 3), getZBit(sample_number / 2), 2, &audio_buffer_B[sample_number]); // left - p += 3; - - sample_number = (AudioGroupCounter * 2) + counter + 1; - pack_AES_subframe(p, getChannelStatusBit(sample_number / 2, 4), getZBit(sample_number / 2), 3, &audio_buffer_B[sample_number]); // right - p += 3; - counter += 2; - } - - // 1 CS (Checksum from DID - UDW) - *p++ = checker(DID_pointer); - - // fill ANC with one dummy for videocolor black - // rest until end of `ANCILLARY_DATA_SAMPLES` will be fill in a loop after call this function - *p++ = 0x040; - } - return p - pp; -} - -// calculate checksumm of ANC (SMPTE 272-M 15.3 Checksum (CS)) -static uint16_t checker(uint16_t *DID_pointer) { - - // Checksumm - uint16_t cs = 0x00; - - // DID - Datablock Identification - cs += (*DID_pointer++) & 0x1FF; // 9 x LSB - - // DBN - Datablock Number - cs += (*DID_pointer++) & 0x1FF; // 9 x LSB - - // DC - DataCounter - cs += (*DID_pointer) & 0x1FF; // 9 x LSB - - // store address of DC an ad to the real value of DC - // DataCounter store - // ´ende´ point to DataCounter - uint16_t *ende = DID_pointer; - // ´ende´ point to last field - ende += (*DID_pointer) & 0xFF; // without parity-Bit and ¬9-Bit - - DID_pointer++; - - // while DID_pointer point to smaller address like 'ende' - while (DID_pointer <= ende) { - cs += (*DID_pointer++) & 0x1FF; // 9 x LSB - } - - // limit to 9Bit, because of overflow of sum - cs = cs & 0x1FF; - - // set bit10 NOT bit9: - // - cs invert - // - & with bitmask '01 0000 0000' - // - shift rest (1xbit)to left - // - add to cs - cs += ((~cs) & 0x100) << 1; - - return cs; -} // end checker - - -/** - * pack 16bit in AES subframe with 3 words (30 bit) and write in ´*p´ - * 10bit-words --> [X],[X+1], [X+2] implements 20bit for audio - * - * BIT 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 - * ##### ### ### ### ### ### ### ### ### ### - * [X] : [ !bit8, a5, a4, a3, a2, a1, a0, ch0, ch1, z ], - * [X+1] : [ !bit8, a14, a13, a12, a11, a10, a9, a8, a7 , a6 ], - * [X+2] : [ !bit8, P, C, U, V, a19, a18, a17, a16, a15 ] - * - * @param *p: Pointer to SDI frame buffer - * @param c: value of AES subframe Channel Status Bit - * @param z: value of AES subframe - * @param ch: channel od AES subframe (value:0,1,2,3) - * @param *audio_samplex: pointer to the audio buffer - **/ -static int pack_AES_subframe(uint16_t *p, int8_t c, int8_t z, int8_t ch, int16_t *audio_samplex) { - - /** - * NOTE: WE JUST SUPPORT ONLY 16BIT SAMPLE SIZE - **/ - - // push 16bit up to 20bit(32bit) - int32_t audio_sample = *audio_samplex; - audio_sample = audio_sample << 4; // Shift by 4 (louder) - - // parity_counter - int8_t parity_counter = 0; - - // 16bit buffer to write 10bit of [X]word,[X+1]word,[X+2]word, - uint16_t buffer = 0; - - //######################################################### - //### WORD X ############################################ - //######################################################### - // word X: !bit8, a5, a4, a3, a2, a1, a0, ch1, ch0, z - // SMPTE 272M s.7 - buffer = z; // z bit every 192bit = 1 - buffer += ch << 1; // ch1 - ch0 - buffer += (audio_sample & 0x3f) << 3; // a5 - a0 - buffer += ((~buffer) & 0x100) << 1; // !bit8 - - // write word ´X´ - *p++ = buffer; - - // count ones - int i = 0; - for (i = 0; i < 9; i++) { - if (buffer & 1 << i) - parity_counter++; - } - - //######################################################### - //### WORD X+1 ############################################ - //######################################################### - // word X+1: !bit8, a14, a13, a12, a11, a10, a9, a8, a7, a6 - // SMPTE 272M s.7 - buffer = 0; - buffer += (audio_sample >> 6) & 0x1ff; // a14 - a6 - buffer += ((~buffer) & 0x100) << 1; // !bit8 - - // write word ´X+1´ - *p++ = buffer; - - // count ones (zähle Einsen) - i = 0; - for (i = 0; i < 9; i++) { - if (buffer & 1 << i) - parity_counter++; - } - - //######################################################### - //### WORD X+2 ############################################ - //######################################################### - // word X+2: !bit8, P, C, U, V, a19, a18, a17, a16, a15 - // SMPTE 272M s.7 - buffer = 0; - buffer += (audio_sample >> 15) & 0x01F; // a15 - a19 - // default of [V][U][C] bits = `0` - //buffer += 1<<5; // V (AES sample validity bit) - //buffer += 1<<6; // U (AES user bit) - //buffer += 1<<7; // C (AES audio channel status bit) - buffer += c << 7; // C (AES audio channel status bit) - - // count ones (zähle Einsen) - for (i = 0; i < 8; i++) { - if (buffer & 1 << i) - parity_counter++; - } - - // if (!parity_counter%2) //else leave the 0 - // buffer+= 1 << 8; // P (AES even parity bit) - // - // buffer += ((~buffer) & 0x100 )<<1; // !bit8 - if ((parity_counter % 2) == 0) { //else leave the 0 - buffer += 512; // 10 0000 0000 // set bit8 = even parity bit and bit9 = !bit8 - } else { - buffer += 256; // 01 0000 0000 // set bit8 = even parity bit and bit9 = !bit8 - } - *p++ = buffer; - - // write word ´X+2´ - *p++ = buffer; - - return 1; -} - -static uint8_t getZBit(int sample_number) { - - // start in SDI line 6 also 18samples later - //sample_number+=192-18; - - if (sample_number % 192 == 0) { - //printf("1 %i\n", sample_number); - return 1; - } else { - //printf("0"); - return 0; - } -} - -static uint8_t getChannelStatusBit(uint16_t sample_number, uint8_t ch) { - - // return value - uint8_t AESChannelStatusBit = 0; - - // start in SDI line 6 also 18samples later - //AESChannelStatusBit=((sample_number+192-18)%192); - // interval in 192bit - AESChannelStatusBit = sample_number % 192; - - // when mulichannelmode is true - if (AESChannelStatusBitArray[31] == 1) { - // set bits for channel - if (AESChannelStatusBit == 30 && ch == 2) - return 1; - if (AESChannelStatusBit == 30 && ch == 4) - return 1; - if (AESChannelStatusBit == 29 && (ch == 4)) - return 1; - if (AESChannelStatusBit == 29 && (ch == 3)) - return 1; - } - return AESChannelStatusBitArray[AESChannelStatusBit]; -} - -static int16_t getNumberOfAudioGroups2Write(int linenumber) { - - // `4:3_VTR`-distribution - if (linenumber >= 11 && linenumber <= 95) { - if ((linenumber - 11) % 14 == 0) { - return 4; - } else { - return 3; - } - } else if (linenumber >= 108 && linenumber <= 220) { - if ((linenumber - 10) % 14 == 0) { - return 4; - } else { - return 3; - } - } else if (linenumber >= 233 && linenumber <= 345) { - if ((linenumber - 9) % 14 == 0) { - return 4; - } else { - return 3; - } - } else if (linenumber >= 358 && linenumber <= 470) { - if ((linenumber - 8) % 14 == 0) { - return 4; - } else { - return 3; - } - } else if (linenumber >= 483 && linenumber <= 595) { - if ((linenumber - 7) % 14 == 0) { - return 4; - } else { - return 3; - } - } else if (linenumber >= 608 && linenumber <= 622) { - if ((linenumber - 6) % 14 == 0) { - return 4; - } else { - return 3; - } - } else { - return 3; - } - - // // `4:3`-distribution - // if(linenumber<=315){ - // if(linenumber>=6 && linenumber<=8){ - // return 0; - // } - // if((linenumber+5)%10==0){ - // return 4; - // }else{ - // return 3; - // } - // }else{ - // if(linenumber>=319 && linenumber<=321){ - // return 0; - // } - // if((linenumber-8)%10==0){ - // return 4; - // }else{ - // return 3; - // } - // } - - // // full-distribution - // if(linenumber<=45){ - // return 4; - // }else{ - // return 3; - // } - - // // fullhalf-distribution - // if (linenumber==625) - // return 4; - // - // if (linenumber%14==0) { - // return 4; - // } else { - // return 3; - // } - -} -static uint8_t getDBN(int my_DBN) { - - return ((my_DBN - 1) % 255) + 1; -} - -/** - * pack8 - pack a line of 8-bit data - * @outbuf: pointer to the output buffer - * @inbuf: pointer to the input buffer - * @count: number of elements in the buffer - * - * Returns a pointer to the next output location. - **/ -static inline uint8_t * -pack8(uint8_t *outbuf, uint16_t *inbuf, size_t count) { - uint16_t *inp = inbuf; - uint8_t *outp = outbuf; - - while (inp < (inbuf + count)) { - *outp++ = *inp++ >> 2; - } - return outp; -} - -/** - * pack10 - pack a line of 10-bit data - * @outbuf: pointer to the output buffer - * @inbuf: pointer to the input buffer - * @count: number of elements in the buffer - * - * Returns a pointer to the next output location. - **/ -static inline uint8_t * pack10(uint8_t *outbuf, uint16_t *inbuf, size_t count) { - - uint16_t *inp = inbuf; - uint8_t *outp = outbuf; - - while (inp < (inbuf + count)) { - *outp++ = *inp & 0xff; - *outp = *inp++ >> 8; - *outp++ += (*inp << 2) & 0xfc; - *outp = *inp++ >> 6; - *outp++ += (*inp << 4) & 0xf0; - *outp = *inp++ >> 4; - *outp++ += (*inp << 6) & 0xc0; - *outp++ = *inp++ >> 2; - } - - return outp; -} -/** - * pack_v210 - pack a line of v210 data - * @outbuf: pointer to the output buffer - * @inbuf: pointer to the input buffer - * @count: number of elements in the buffer - * - * Returns a pointer to the next output location. - **/ -static inline uint8_t * pack_v210(uint8_t *outbuf, uint16_t *inbuf, size_t count) { - - uint16_t *inp = inbuf; - uint8_t *outp = outbuf; - - count = (count / 96) * 96 + ((count % 96) ? 96 : 0); - while (inp < (inbuf + count)) { - *outp++ = *inp & 0xff; - *outp = *inp++ >> 8; - *outp++ += (*inp << 2) & 0xfc; - *outp = *inp++ >> 6; - *outp++ += (*inp << 4) & 0xf0; - *outp++ = *inp++ >> 4; - } - return outp; -} - -// Clean up -static int sdimaster_close() { - - free(line_buffer); - free(data); - - if (fh_sdi_audio) - close(fh_sdi_audio); - if (fh_sdi_video) - close(fh_sdi_video); - - return 1; -} - -/** - * mkline - generate one line - * @buf: pointer to a buffer - * @info: pointer to a line information structure - * @pattern: pattern - * - * Returns a negative error code on failure and zero on success. - **/ -static int mkline(unsigned short int *buf, const struct line_info *info, unsigned int pattern) { - const unsigned int b = 205; - unsigned short int *p = buf, *endp; - unsigned int samples = info->blanking ? info->fmt->samples_per_line : info->fmt->active_samples_per_line; - - if (info->blanking) { - /* EAV */ - *p++ = 0x3ff; - *p++ = 0x000; - *p++ = 0x000; - *p++ = info->xyz->eav; - /* Horizontal blanking */ - while (p < (buf + 272)) { - *p++ = 0x200; - *p++ = 0x040; - *p++ = 0x200; - *p++ = 0x040; - } - /* SAV */ - *p++ = 0x3ff; - *p++ = 0x000; - *p++ = 0x000; - *p++ = info->xyz->sav; - } - /* Active region */ - endp = p; - switch (pattern) { - default: - case VERT_BLANKING: - while (p < (buf + samples)) { - *p++ = 0x200; - *p++ = 0x040; - *p++ = 0x200; - *p++ = 0x040; - } - break; - case BLACK: /* black line (filler for FMT_480i5994 ) */ - while (p < (buf + samples)) { - *p++ = 0x200; - *p++ = 0x040; - *p++ = 0x200; - *p++ = 0x040; - } - break; - case GREEN: /* green line for test purpose */ - while (p < (buf + samples)) { - *p++ = 289; - *p++ = 450; - *p++ = 231; - *p++ = 450; - } - break; - case MAIN_SET: - /* 75% gray */ - endp += b + 1; - while (p < endp) { - *p++ = 512; - *p++ = 721; - *p++ = 512; - *p++ = 721; - } - /* 75% yellow */ - endp += b + 1; - while (p < endp) { - *p++ = 176; - *p++ = 646; - *p++ = 567; - *p++ = 646; - } - /* 75% cyan */ - endp += b + 1; - while (p < endp) { - *p++ = 625; - *p++ = 525; - *p++ = 176; - *p++ = 525; - } - /* 75% green */ - endp += b - 1; - while (p < endp) { - *p++ = 289; - *p++ = 450; - *p++ = 231; - *p++ = 450; - } - /* 75% magenta */ - endp += b + 1; - while (p < endp) { - *p++ = 735; - *p++ = 335; - *p++ = 793; - *p++ = 335; - } - /* 75% red */ - endp += b + 1; - while (p < endp) { - *p++ = 399; - *p++ = 260; - *p++ = 848; - *p++ = 260; - } - /* 75% blue */ - while (p < (buf + samples)) { - *p++ = 848; - *p++ = 139; - *p++ = 457; - *p++ = 139; - } - break; - case CHROMA_SET: - /* 75% blue */ - endp += b + 1; - while (p < endp) { - *p++ = 848; - *p++ = 139; - *p++ = 457; - *p++ = 139; - } - /* black */ - endp += b + 1; - while (p < endp) { - *p++ = 0x200; - *p++ = 0x040; - *p++ = 0x200; - *p++ = 0x040; - } - /* 75% magenta */ - endp += b + 1; - while (p < endp) { - *p++ = 735; - *p++ = 335; - *p++ = 793; - *p++ = 335; - } - /* black */ - endp += b - 1; - while (p < endp) { - *p++ = 0x200; - *p++ = 0x040; - *p++ = 0x200; - *p++ = 0x040; - } - /* 75% cyan */ - endp += b + 1; - while (p < endp) { - *p++ = 625; - *p++ = 525; - *p++ = 176; - *p++ = 525; - } - /* black */ - endp += b + 1; - while (p < endp) { - *p++ = 0x200; - *p++ = 0x040; - *p++ = 0x200; - *p++ = 0x040; - } - /* 75% gray */ - while (p < (buf + samples)) { - *p++ = 512; - *p++ = 721; - *p++ = 512; - *p++ = 721; - } - break; - case BLACK_SET: - /* -I */ - endp += 257; - while (p < endp) { - *p++ = 624; - *p++ = 231; - *p++ = 390; - *p++ = 231; - } - /* white */ - endp += 257; - while (p < endp) { - *p++ = 0x200; - *p++ = 940; - *p++ = 0x200; - *p++ = 940; - } - /* +Q */ - endp += 257; - while (p < endp) { - *p++ = 684; - *p++ = 177; - *p++ = 591; - *p++ = 177; - } - /* black */ - endp += 257; - while (p < endp) { - *p++ = 0x200; - *p++ = 0x040; - *p++ = 0x200; - *p++ = 0x040; - } - /* blacker than black */ - endp += 68; - while (p < endp) { - *p++ = 0x200; - *p++ = 29; - *p++ = 0x200; - *p++ = 29; - } - /* black */ - endp += 68 + 2; - while (p < endp) { - *p++ = 0x200; - *p++ = 0x040; - *p++ = 0x200; - *p++ = 0x040; - } - /* whiter than black */ - endp += 68; - while (p < endp) { - *p++ = 0x200; - *p++ = 99; - *p++ = 0x200; - *p++ = 99; - } - /* black */ - while (p < (buf + samples)) { - *p++ = 0x200; - *p++ = 0x040; - *p++ = 0x200; - *p++ = 0x040; - } - break; - } - return 0; -} - -static int setSDIVideoProperties(enum sdi_setting_video_e setting, char * value, char * device) { - - const char fmt[] = "/sys/class/sdivideo/sdivideo%cx%i/%s"; - struct stat buf; - int num; - char type, name[256], data[256]; - char *endptr; - - /* Get the sysfs info */ - memset(&buf, 0, sizeof(buf)); - - /** - * Stat the file, fills the structure with info about the file - * Get the major number from device node - **/ - if (stat(device, &buf) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to get the file status"); - return -1; - } - - /* Check if it is a character device or not */ - if (!S_ISCHR (buf.st_mode)) { - fprintf(stderr, "%s: not a character device\n", device); - return -1; - } - - /* Check the minor number to determine if it is a receive or transmit device */ - type = (buf.st_rdev & 0x0080) ? 'r' : 't'; - - /* Get the receiver or transmitter number */ - num = buf.st_rdev & 0x007f; - - /* Build the path to sysfs file */ - snprintf(name, sizeof(name), fmt, type, num, "dev"); - memset(data, 0, sizeof(data)); - - /* Read sysfs file (dev) */ - if (util_read(name, data, sizeof(data)) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to get the device number"); - return -1; - } - /* Compare the major number taken from sysfs file to the one taken from device node */ - if (strtoul(data, &endptr, 0) != (buf.st_rdev >> 8)) { - fprintf(stderr, "%s: not a SMPTE 292M/SMPTE 259M-C device\n", device); - return -1; - } - if (*endptr != ':') { - fprintf(stderr, "%s: error reading %s\n", device, name); - return -1; - } - - // Which setting do we write - if (setting == SETTING_BUFFER_NUMBER_VIDEO) { - snprintf(name, sizeof(name), fmt, type, num, "buffers"); - snprintf(data, sizeof(data), "%s\n", value); - if (util_write(name, data, sizeof(data)) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to set the number of buffers"); - return -1; - } - printf("\tSet number of buffers = %s\n", value); - } else if (setting == SETTING_BUFFER_SIZE_VIDEO) { - snprintf(name, sizeof(name), fmt, type, num, "bufsize"); - snprintf(data, sizeof(data), "%s\n", value); - if (util_write(name, data, sizeof(data)) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to set the buffer size"); - return -1; - } - printf("\tSet buffer size = %s Bytes\n", value); - } else if (setting == SETTING_CLOCK_SOURCE) { - snprintf(name, sizeof(name), fmt, type, num, "clock_source"); - snprintf(data, sizeof(data), "%s\n", value); - if (util_write(name, data, sizeof(data)) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to set the clock source"); - return -1; - } - printf("\tSet clock source = %s\n", value); - } else if (setting == SETTING_DATA_MODE) { - snprintf(name, sizeof(name), fmt, type, num, "mode"); - snprintf(data, sizeof(data), "%s\n", value); - if (util_write(name, data, sizeof(data)) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to set the interface operating mode"); - return -1; - } - printf("\tSet data mode = %s\n", value); - } else if (setting == SETTING_FRAME_MODE) { - snprintf(name, sizeof(name), fmt, type, num, "frame_mode"); - snprintf(data, sizeof(data), "%s\n", value); - if (util_write(name, data, sizeof(data)) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to set the interface frame mode"); - return -1; - } - printf("\tSet frame mode = %s\n", value); - } - - return 0; - -} - -static int setSDIAudioProperties(enum sdi_setting_audio_e setting, char * value, char * device) { - const char fmt[] = "/sys/class/sdiaudio/sdiaudio%cx%i/%s"; - struct stat buf; - int num; - char type, name[256], data[256]; - char *endptr; - - /* Get the sysfs info */ - memset(&buf, 0, sizeof(buf)); - if (stat(device, &buf) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to get the file status"); - return -1; - } - if (!S_ISCHR (buf.st_mode)) { - fprintf(stderr, "%s: not a character device\n", device); - return -1; - } - type = (buf.st_rdev & 0x0080) ? 'r' : 't'; - num = buf.st_rdev & 0x007f; - snprintf(name, sizeof(name), fmt, type, num, "dev"); - memset(data, 0, sizeof(data)); - if (util_read(name, data, sizeof(data)) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to get the device number"); - return -1; - } - - if (strtoul(data, &endptr, 0) != (buf.st_rdev >> 8)) { - fprintf(stderr, "%s: not an audio device\n", device); - return -1; - } - if (*endptr != ':') { - fprintf(stderr, "%s: error reading %s\n", device, name); - return -1; - } - - if (setting == SETTING_BUFFER_NUMBER_AUDIO) { - snprintf(name, sizeof(name), fmt, type, num, "buffers"); - snprintf(data, sizeof(data), "%s\n", value); - - if (util_write(name, data, sizeof(data)) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to set the number of buffers"); - return -1; - } - printf("\tSet number of buffers = %s\n", value); - } else if (setting == SETTING_BUFFER_SIZE_AUDIO) { - snprintf(name, sizeof(name), fmt, type, num, "bufsize"); - snprintf(data, sizeof(data), "%s\n", value); - if (util_write(name, data, sizeof(data)) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to set the buffer size"); - return -1; - } - printf("\tSet buffer size = %s Bytes\n", value); - } else if (setting == SETTING_SAMPLE_SIZE) { - snprintf(name, sizeof(name), fmt, type, num, "sample_size"); - snprintf(data, sizeof(data), "%s\n", value); - if (util_write(name, data, sizeof(data)) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to set the interface audio sample size"); - return -1; - } - switch (atol(value)) { - case SDIAUDIO_CTL_AUDSAMP_SZ_16: - printf("\tAssuming 16-bit audio.\n"); - break; - case SDIAUDIO_CTL_AUDSAMP_SZ_24: - printf("\tAssuming 24-bit audio.\n"); - break; - case SDIAUDIO_CTL_AUDSAMP_SZ_32: - printf("\tAssuming 32-bit audio.\n"); - break; - default: - printf("\tSet audio sample size = %lu.\n", atol(value)); - break; - } - } else if (setting == SETTING_SAMPEL_RATE) { - snprintf(name, sizeof(name), fmt, type, num, "sample_rate"); - snprintf(data, sizeof(data), "%lu\n", atol(value)); - if (util_write(name, data, sizeof(data)) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to set the interface audio sample rate"); - return -1; - } - switch (atoi(value)) { - case 32000: - printf("\tAssuming 32 kHz audio.\n"); - break; - case 44100: - printf("\tAssuming 44.1 kHz audio.\n"); - break; - case 48000: - printf("\tAssuming 48 kHz audio.\n"); - break; - default: - printf("\tSet audio sample rate = %lu.\n", atol(value)); - break; - } - } else if (setting == SETTING_CHANNELS) { - snprintf(name, sizeof(name), fmt, type, num, "channels"); - snprintf(data, sizeof(data), "%lu\n", atol(value)); - if (util_write(name, data, sizeof(data)) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to set " - "the interface audio channel enable"); - return -1; - } - switch (atol(value)) { - case SDIAUDIO_CTL_AUDCH_EN_0: - printf("\tDisabling audio.\n"); - break; - case SDIAUDIO_CTL_AUDCH_EN_2: - printf("\tAssuming 2 channels of audio.\n"); - break; - case SDIAUDIO_CTL_AUDCH_EN_4: - printf("\tAssuming 4 channels of audio.\n"); - break; - case SDIAUDIO_CTL_AUDCH_EN_6: - printf("\tAssuming 6 channels of audio.\n"); - break; - case SDIAUDIO_CTL_AUDCH_EN_8: - printf("\tAssuming 8 channels of audio.\n"); - break; - default: - printf("\tSet audio channel enable = %lu.\n", atol(value)); - break; - } - } else if (setting == SETTING_NON_AUDIO) { - snprintf(name, sizeof(name), fmt, type, num, "non_audio"); - snprintf(data, sizeof(data), "0x%04lX\n", atol(value)); - if (util_write(name, data, sizeof(data)) < 0) { - fprintf(stderr, "%s: ", device); - perror("unable to set " - "the interface non-audio"); - return -1; - } - switch (atol(value)) { - case 0x0000: - printf("\tPassing PCM audio.\n"); - break; - case 0x00ff: - printf("\tPassing non-audio.\n"); - break; - default: - printf("\tSet non-audio = 0x%04lX.\n", atol(value)); - break; - } - } - - return 0; -} - -static ssize_t util_read(const char *name, char *buf, size_t count) { - ssize_t fd, ret; - - if ((fd = open(name, O_RDONLY)) < 0) { - return fd; - } - ret = read(fd, buf, count); - close(fd); - return ret; -} - -static ssize_t util_write(const char *name, const char *buf, size_t count) { - ssize_t fd, ret; - - if ((fd = open(name, O_WRONLY)) < 0) { - return fd; - } - ret = write(fd, buf, count); - close(fd); - return ret; -} - -static char * itoa(uint64_t i) { - - if (i == 0) - return strdup("0"); - - char * mystring = (char *) malloc(50); - sprintf(mystring, "%"PRIu64, i); - - return mystring; -} diff --git a/src/modules/linsys/sdi_generator.h b/src/modules/linsys/sdi_generator.h deleted file mode 100644 index 66caa7ee0..000000000 --- a/src/modules/linsys/sdi_generator.h +++ /dev/null @@ -1,319 +0,0 @@ -/** - * sdi_generator.h - **/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#ifndef SDI_GENERATOR_H_ -#define SDI_GENERATOR_H_ - -// definitions are only for SD NTSC (mkline funktion for test pattern) -#define VERT_BLANKING 0 -#define MAIN_SET 1 -#define CHROMA_SET 2 -#define BLACK_SET 3 -#define BLACK 4 -#define GREEN 5 - -// defines for SD SDI with blanking -#define ANCILLARY_DATA_SAMPLES 280 -#define FIELD_1 1 -#define FIELD_2 2 -#define VERT_BLANKING 0 -#define ACTIVE_VIDEO 1 - -// Master SDI device -#define SDI_IOC_MAGIC '=' -#define SDI_IOC_TXGETEVENTS _IOR(SDI_IOC_MAGIC, 2, unsigned int) - -// Transmitter event flag bit locations -#define SDI_EVENT_TX_BUFFER_ORDER 0 -#define SDI_EVENT_TX_BUFFER (1 << SDI_EVENT_TX_BUFFER_ORDER) -#define SDI_EVENT_TX_FIFO_ORDER 1 -#define SDI_EVENT_TX_FIFO (1 << SDI_EVENT_TX_FIFO_ORDER) -#define SDI_EVENT_TX_DATA_ORDER 2 -#define SDI_EVENT_TX_DATA (1 << SDI_EVENT_TX_DATA_ORDER) - -// part of the linsys sdiaudio.h - -#define SDIAUDIO_IOC_TXGETCAP _IOR(SDIAUDIO_IOC_MAGIC, 1, unsigned int) -#define SDIAUDIO_IOC_TXGETEVENTS _IOR(SDIAUDIO_IOC_MAGIC, 2, unsigned int) -#define SDIAUDIO_IOC_TXGETBUFLEVEL _IOR(SDIAUDIO_IOC_MAGIC, 3, unsigned int) -#define SDIAUDIO_IOC_TXGETTXD _IOR(SDIAUDIO_IOC_MAGIC, 4, int) - -#define SDIAUDIO_IOC_MAGIC '~' /* This ioctl magic number is currently free. See - * /usr/src/linux/Documentation/ioctl-number.txt */ -/* Transmitter event flag bit locations */ -#define SDIAUDIO_EVENT_TX_BUFFER_ORDER 0 -#define SDIAUDIO_EVENT_TX_BUFFER (1 << SDIAUDIO_EVENT_TX_BUFFER_ORDER) -#define SDIAUDIO_EVENT_TX_FIFO_ORDER 1 -#define SDIAUDIO_EVENT_TX_FIFO (1 << SDIAUDIO_EVENT_TX_FIFO_ORDER) -#define SDIAUDIO_EVENT_TX_DATA_ORDER 2 -#define SDIAUDIO_EVENT_TX_DATA (1 << SDIAUDIO_EVENT_TX_DATA_ORDER) - -// Filehandler for sdi output -static int fh_sdi_video; -static int fh_sdi_audio; - -#define MAX_SAMPLES_PER_LINE (2*2750) -#define MAX_LINES_PER_FRAME 1125 -#define MAX_AUDIO_STREAMS (8) -// max. audio samples per frame -#define MAX_AUDIO_SAMPLES (2002*2) -/** - * 23.98Hz = fix:{2002} - * 24Hz = fix:{2000} - * 25Hz = fix:{1920} - * 29.97Hz = varies:{1601,1602,1602} - * 30Hz = fix:{1600} - **/ - -#define MAX_SDI_HEIGHT 1125 // HD-SDI -#define MAX_SDI_WIDTH 2750 // HD-SDI (FMT_1080p24 has up to 2750) -#define MAX_SDI_FRAMESIZE (MAX_SDI_HEIGHT*MAX_SDI_WIDTH*2) // SDI frame size, (2 Pixels are represented by 4 bytes, yuyv422) -struct source_format { - unsigned int lines_per_frame; - unsigned int active_lines_per_frame; - unsigned int samples_per_line; - unsigned int active_samples_per_line; - unsigned int interlaced; -}; - -struct audio_format { - - mlt_audio_format aformat; // default: mlt_audio_pcm - uint16_t samples; // default 2*1920 - uint16_t sample_rate; // default 48000 - /** - * 0 channels = audio disabled, transmit only - * 2 channels (stereo) - * 4 channels - * 6 channels - * 8 channels - **/ - int channels; // default 2 (stereo) -}; - -/** - * SDI DEVICE FILE SETTINGS AND MODES - **/ -enum sdi_setting_video_e { - - SETTING_BUFFER_NUMBER_VIDEO = 0, SETTING_BUFFER_SIZE_VIDEO = 1, SETTING_CLOCK_SOURCE = 2, SETTING_DATA_MODE = 3, SETTING_FRAME_MODE = 4 -}; -enum sdi_setting_audio_e { - - SETTING_BUFFER_NUMBER_AUDIO = 0, - SETTING_BUFFER_SIZE_AUDIO = 1, - SETTING_SAMPLE_SIZE = 2, - SETTING_CHANNELS = 3, - SETTING_SAMPEL_RATE = 4, - SETTING_NON_AUDIO = 5 -}; - -static int sdi_frame_mode = 0; - -/* Frame mode settings */ -#define SDIVIDEO_CTL_UNLOCKED 0 -#define SDIVIDEO_CTL_SMPTE_125M_486I_59_94HZ 1 -#define SDIVIDEO_CTL_BT_601_576I_50HZ 2 -#define SDIVIDEO_CTL_SMPTE_260M_1035I_60HZ 5 -#define SDIVIDEO_CTL_SMPTE_260M_1035I_59_94HZ 6 -#define SDIVIDEO_CTL_SMPTE_295M_1080I_50HZ 7 -#define SDIVIDEO_CTL_SMPTE_274M_1080I_60HZ 8 -#define SDIVIDEO_CTL_SMPTE_274M_1080PSF_30HZ 9 -#define SDIVIDEO_CTL_SMPTE_274M_1080I_59_94HZ 10 -#define SDIVIDEO_CTL_SMPTE_274M_1080PSF_29_97HZ 11 -#define SDIVIDEO_CTL_SMPTE_274M_1080I_50HZ 12 -#define SDIVIDEO_CTL_SMPTE_274M_1080PSF_25HZ 13 -#define SDIVIDEO_CTL_SMPTE_274M_1080PSF_24HZ 14 -#define SDIVIDEO_CTL_SMPTE_274M_1080PSF_23_98HZ 15 -#define SDIVIDEO_CTL_SMPTE_274M_1080P_30HZ 16 -#define SDIVIDEO_CTL_SMPTE_274M_1080P_29_97HZ 17 -#define SDIVIDEO_CTL_SMPTE_274M_1080P_25HZ 18 -#define SDIVIDEO_CTL_SMPTE_274M_1080P_24HZ 19 -#define SDIVIDEO_CTL_SMPTE_274M_1080P_23_98HZ 20 -#define SDIVIDEO_CTL_SMPTE_296M_720P_60HZ 21 -#define SDIVIDEO_CTL_SMPTE_296M_720P_59_94HZ 22 -#define SDIVIDEO_CTL_SMPTE_296M_720P_50HZ 23 -#define SDIVIDEO_CTL_SMPTE_296M_720P_30HZ 24 -#define SDIVIDEO_CTL_SMPTE_296M_720P_29_97HZ 25 -#define SDIVIDEO_CTL_SMPTE_296M_720P_25HZ 26 -#define SDIVIDEO_CTL_SMPTE_296M_720P_24HZ 27 -#define SDIVIDEO_CTL_SMPTE_296M_720P_23_98HZ 28 - -/* Audio sample size */ -#define SDIAUDIO_CTL_AUDSAMP_SZ_16 16 /* 16 bit */ -#define SDIAUDIO_CTL_AUDSAMP_SZ_24 24 /* 24 bit */ -#define SDIAUDIO_CTL_AUDSAMP_SZ_32 32 /* 32 bit */ - -/* Audio channel enable */ -#define SDIAUDIO_CTL_AUDCH_EN_0 0 /* 0 channel/disable audio */ -#define SDIAUDIO_CTL_AUDCH_EN_2 2 /* 2 channel */ -#define SDIAUDIO_CTL_AUDCH_EN_4 4 /* 4 channel */ -#define SDIAUDIO_CTL_AUDCH_EN_6 6 /* 6 channel */ -#define SDIAUDIO_CTL_AUDCH_EN_8 8 /* 8 channel */ - -static char * itoa(uint64_t i); -static ssize_t util_read(const char *name, char *buf, size_t count); -static ssize_t util_write(const char *name, const char *buf, size_t count); -static int setSDIVideoProperties(enum sdi_setting_video_e setting, char * value, char * device); -static int setSDIAudioProperties(enum sdi_setting_audio_e setting, char * value, char * device); - -// HD -static const struct source_format FMT_1080i60 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2200, - .active_samples_per_line = 2*1920, .interlaced = 1 }; - -static const struct source_format FMT_1080i5994 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2200, - .active_samples_per_line = 2*1920, .interlaced = 1 }; - -static const struct source_format FMT_1080i50 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2640, - .active_samples_per_line = 2*1920, .interlaced = 1 }; - -static const struct source_format FMT_1080p30 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2200, - .active_samples_per_line = 2*1920, .interlaced = 0 }; - -static const struct source_format FMT_1080p2997 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2200, - .active_samples_per_line = 2*1920, .interlaced = 0 }; - -static const struct source_format FMT_1080p25 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2640, - .active_samples_per_line = 2*1920, .interlaced = 0 }; - -static const struct source_format FMT_1080p24 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2750, - .active_samples_per_line = 2*1920, .interlaced = 0 }; - -static const struct source_format FMT_1080p2398 = { .lines_per_frame = 1125, .active_lines_per_frame = 1080, .samples_per_line = 2*2750, - .active_samples_per_line = 2*1920, .interlaced = 0 }; - -static const struct source_format FMT_720p60 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*1650, - .active_samples_per_line = 2*1280, .interlaced = 0 }; - -static const struct source_format FMT_720p5994 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*1650, - .active_samples_per_line = 2*1280, .interlaced = 0 }; - -static const struct source_format FMT_720p50 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*1980, - .active_samples_per_line = 2*1280, .interlaced = 0 }; - -static const struct source_format FMT_720p30 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*3300, - .active_samples_per_line = 2*1280, .interlaced = 0 }; - -static const struct source_format FMT_720p2997 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*3300, - .active_samples_per_line = 2*1280, .interlaced = 0 }; - -static const struct source_format FMT_720p25 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*3960, - .active_samples_per_line = 2*1280, .interlaced = 0 }; - -static const struct source_format FMT_720p24 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*4125, - .active_samples_per_line = 2*1280, .interlaced = 0 }; - -static const struct source_format FMT_720p2398 = { .lines_per_frame = 750, .active_lines_per_frame = 720, .samples_per_line = 2*4125, - .active_samples_per_line = 2*1280, .interlaced = 0 }; - -// SD PAL -static const struct source_format FMT_576i50 = { .lines_per_frame = 625, .active_lines_per_frame = 576, .samples_per_line = 2*864 /*1728*/, - .active_samples_per_line = 2*720 /* 720xY, 360xCb, 360xCr */, .interlaced = 1 }; - -// SD NTSC; 486 video lines -static const struct source_format FMT_486i5994 = { .lines_per_frame = 525, .active_lines_per_frame = 486, .samples_per_line = 2*858 /*1716*/, - .active_samples_per_line = 2*720 /* 720xY, 360xCb, 360xCr */, .interlaced = 1 }; - -// SD NTSC; 480 video lines, 6 lines opt. video data -/** - * sames as FMT_486i5994 but the first 6 lines will be filled with SDI-BLACK - * or can be used for opt. video data (s.SMPTE) - */ -static const struct source_format FMT_480i5994 = { .lines_per_frame = 525, .active_lines_per_frame = 486, .samples_per_line = 2*858 /*1716*/, - .active_samples_per_line = 2*720 /* 720xY, 360xCb, 360xCr */, .interlaced = 1 }; - -struct trs { - unsigned short int sav; - unsigned short int eav; -}; - -static const struct trs FIELD_1_ACTIVE = { .sav = 0x200, .eav = 0x274 }; -static const struct trs FIELD_1_VERT_BLANKING = { .sav = 0x2ac, .eav = 0x2d8 }; -static const struct trs FIELD_2_ACTIVE = { .sav = 0x31c, .eav = 0x368 }; -static const struct trs FIELD_2_VERT_BLANKING = { .sav = 0x3b0, .eav = 0x3c4 }; - -struct line_info { - const struct source_format *fmt; - unsigned int ln; - const struct trs *xyz; - uint8_t blanking; -}; - -struct SDI_atr { - int status; - int *fh; - uint8_t *data; - size_t framesize; -} SDI_atr; - -// 192bit for AESChannelStatusBits -uint8_t AESChannelStatusBitArray[192]; // beta array -//uint8_t AESChannelStatusBitArray[24]; // TODO better way for 24x8bit !!! - -// buffer for one sdi line -uint16_t * line_buffer; -// counter for active line number -uint16_t active_video_line; -// buffer for sdi frame size -uint64_t sdi_frame_size; -// buffer for the complete SDI frame -uint8_t * data; - -static char * device_file_video; -static char * device_file_audio; -static struct line_info info; -static uint8_t *(*pack)(uint8_t *outbuf, unsigned short int *inbuf, size_t count); -static size_t elements; -static unsigned int samples; - -// functions -static int sdi_init(char *device_video, char *device_audio, uint8_t blanking, mlt_profile myProfile, const struct audio_format * audio_format); - -static int sdimaster_close(); - -static int sdi_playout(uint8_t *vBuffer, int16_t aBuffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], const struct audio_format * audio_format, int audio_streams, - int my_DBN); - -static int mkline(unsigned short int *buf, const struct line_info *info, unsigned int pattern); - -static inline int create_HD_SDI_Line(uint16_t *buf, const struct line_info *info, uint16_t active_video_line, unsigned int active, uint8_t *video_buffer); -static inline int create_SD_SDI_Line(uint16_t *buf, const struct line_info *info, int field, int active, uint8_t *video_buffer, - int16_t audio_buffer[MAX_AUDIO_STREAMS][MAX_AUDIO_SAMPLES], int linenumber_sdiframe, int active_video_line, int my_DBN, int16_t AudioGroupCounter, - int16_t AudioGroups2Write, int audio_streams); - -static int writeANC(uint16_t *p, int linenumber_sdiframe, uint16_t DID, int my_DBN, int16_t *audio_buffer_A, int16_t *audio_buffer_B, - int16_t AudioDataPacketCounter, int16_t AudioGroups2Write); -static uint16_t checker(uint16_t *DID_pointer); - -static uint8_t getZBit(int sample_number); -static uint8_t getChannelStatusBit(uint16_t sample_number, uint8_t ch); -static int16_t getNumberOfAudioGroups2Write(int linenuber); - -static uint8_t getDBN(int my_DBN); - -static inline uint8_t *pack8(uint8_t *outbuf, uint16_t *inbuf, size_t count); // alias 'pack_uyvy()' -static inline uint8_t *pack10(uint8_t *outbuf, uint16_t *inbuf, size_t count); -static inline uint8_t *pack_v210(uint8_t *outbuf, uint16_t *inbuf, size_t count); - -static int pack_AES_subframe(uint16_t *p, int8_t c, int8_t z, int8_t ch, int16_t *audio_sample); - -#endif /* SDI_GENERATOR_H_ */ diff --git a/src/modules/lumas/CMakeLists.txt b/src/modules/lumas/CMakeLists.txt deleted file mode 100644 index dbc340f7f..000000000 --- a/src/modules/lumas/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -add_executable(luma luma.c) -target_link_libraries(luma mlt) - -# luma requires libmlt to work, so we set the output directory for luma to the location of this library -set_target_properties(luma PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/src/framework") - -function(create_lumas dir w h bpp) - set(${dir} - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma01.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma02.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma03.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma04.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma05.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma06.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma07.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma08.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma09.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma10.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma11.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma12.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma13.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma14.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma15.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma16.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma17.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma18.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma19.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma20.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma21.pgm - ${CMAKE_CURRENT_BINARY_DIR}/${dir}/luma22.pgm - ) - add_custom_command(OUTPUT ${${dir}} DEPENDS luma - COMMAND ${CMAKE_COMMAND} -E make_directory ${dir} - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma01.pgm - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma02.pgm -bands ${h} - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma03.pgm -hmirror 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma04.pgm -bands ${h} -vmirror 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma05.pgm -offset 32768 -dmirror 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma06.pgm -offset 32768 -dmirror 1 -flip 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma07.pgm -offset 32768 -dmirror 1 -quart 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma08.pgm -offset 32768 -dmirror 1 -quart 1 -flip 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma09.pgm -bands 12 -rband 0 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma10.pgm -bands 12 -rband 0 -rotate 1 -flop 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma11.pgm -bands 12 -rband 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma12.pgm -bands 12 -rband 1 -vmirror 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma13.pgm -bands 12 -rband 1 -rotate 1 -flop 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma14.pgm -bands 12 -rband 1 -rotate 1 -flop 1 -vmirror 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma15.pgm -offset 32768 -dmirror 1 -hmirror 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma16.pgm -type 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma17.pgm -type 1 -bands 2 -rband 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma18.pgm -type 2 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma19.pgm -type 2 -quart 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma20.pgm -type 2 -quart 1 -flip 1 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma21.pgm -type 2 -quart 1 -bands 2 - COMMAND luma -w ${w} -h ${h} -bpp ${bpp} ${dir}/luma22.pgm -type 3) - add_custom_target(${dir} ALL DEPENDS ${${dir}}) - install(FILES ${${dir}} DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/lumas/${dir}) -endfunction() - -create_lumas(PAL 720 576 16) -create_lumas(NTSC 720 480 16) -create_lumas(16_9 1920 1080 16) -create_lumas(9_16 1080 1920 16) -create_lumas(square 1080 1080 16) diff --git a/src/modules/lumas/Makefile b/src/modules/lumas/Makefile deleted file mode 100644 index efc87a4c3..000000000 --- a/src/modules/lumas/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -CFLAGS += -I../.. - -LDFLAGS += -L../../framework -lmlt - -include ../../../config.mak - -all: luma create_lumas - @./create_lumas - -luma: luma.o -# When cross-compiling, use the host OS compiler to build the luma -# binary because the files are generated at build time. -# Strips the CROSS prefix from the C compiler variable. -ifdef CROSS - $(subst $(CROSS),,$(CC)) -o $@ luma.o $(LDFLAGS) -else - $(CC) -o $@ luma.o $(LDFLAGS) -endif - -create_lumas: - -depend: luma.c - $(CC) -MM $(CFLAGS) $^ 1>.depend - -distclean: - rm -rf luma 9_16 16_9 NTSC PAL square - -clean: - rm -f luma luma.o .executed - -install: all - install -d "$(DESTDIR)$(mltdatadir)/lumas/9_16" - install -d "$(DESTDIR)$(mltdatadir)/lumas/16_9" - install -d "$(DESTDIR)$(mltdatadir)/lumas/NTSC" - install -d "$(DESTDIR)$(mltdatadir)/lumas/PAL" - install -d "$(DESTDIR)$(mltdatadir)/lumas/square" - install -m 644 9_16/* "$(DESTDIR)$(mltdatadir)/lumas/9_16" - install -m 644 16_9/* "$(DESTDIR)$(mltdatadir)/lumas/16_9" - install -m 644 NTSC/* "$(DESTDIR)$(mltdatadir)/lumas/NTSC" - install -m 644 PAL/* "$(DESTDIR)$(mltdatadir)/lumas/PAL" - install -m 644 square/* "$(DESTDIR)$(mltdatadir)/lumas/square" diff --git a/src/modules/lumas/configure b/src/modules/lumas/configure deleted file mode 100755 index 4d980d003..000000000 --- a/src/modules/lumas/configure +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -if [ "$help" = "1" ] -then - cat << EOF -Luma options: - - --enable-lumas This must be explicitly enabled since they can now - be generated dynamically. - --luma-compress - Produce compressed (png) lumas - --luma-8bpp - Produce 8 bit pgm lumas (default is 16 bit) - -EOF - -else - - rm -f .8bit .compress .executed - - for i in "$@" - do - case $i in - --enable-lumas ) lumas_enabled=1;; - --luma-compress ) touch .compress .8bit ;; - --luma-8bit ) touch .8bit ;; - esac - done - - if [ "$lumas_enabled" != "1" ]; then - echo "- not explicitly enabled: disabling" - touch ../disable-lumas - exit 0 - fi - -fi - diff --git a/src/modules/lumas/create_lumas b/src/modules/lumas/create_lumas deleted file mode 100755 index 943911b13..000000000 --- a/src/modules/lumas/create_lumas +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/sh - -[ \( -d PAL \) -a \( ! $0 -nt .executed \) ] && exit 0 - -if [ "$(uname -s)" = "Darwin" ]; then - export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../framework -elif uname -s | grep -iq mingw; then - export PATH=$PATH:../../framework -else - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../framework -fi - -bpp=16 -[ -f .8bit ] && bpp=8 - -for i in PAL NTSC 16_9 9_16 square -do - mkdir -p $i - rm -f $i/*.pgm $i/*.png - - case $i in - NTSC) - w=720 - h=480 - ;; - PAL) - w=720 - h=576 - ;; - 16_9) - w=1920 - h=1080 - ;; - 9_16) - w=1080 - h=1920 - ;; - square) - w=1080 - h=1080 - ;; - esac - ./luma -w $w -h $h -bpp $bpp $i/luma01.pgm - ./luma -w $w -h $h -bpp $bpp -bands $h $i/luma02.pgm - ./luma -w $w -h $h -bpp $bpp -hmirror 1 $i/luma03.pgm - ./luma -w $w -h $h -bpp $bpp -bands $h -vmirror 1 $i/luma04.pgm - ./luma -w $w -h $h -bpp $bpp -offset 32768 -dmirror 1 $i/luma05.pgm - ./luma -w $w -h $h -bpp $bpp -offset 32768 -dmirror 1 -flip 1 $i/luma06.pgm - ./luma -w $w -h $h -bpp $bpp -offset 32768 -dmirror 1 -quart 1 $i/luma07.pgm - ./luma -w $w -h $h -bpp $bpp -offset 32768 -dmirror 1 -quart 1 -flip 1 $i/luma08.pgm - ./luma -w $w -h $h -bpp $bpp -bands 12 -rband 0 $i/luma09.pgm - ./luma -w $w -h $h -bpp $bpp -bands 12 -rband 0 -rotate 1 -flop 1 $i/luma10.pgm - ./luma -w $w -h $h -bpp $bpp -bands 12 -rband 1 $i/luma11.pgm - ./luma -w $w -h $h -bpp $bpp -bands 12 -rband 1 -vmirror 1 $i/luma12.pgm - ./luma -w $w -h $h -bpp $bpp -bands 12 -rband 1 -rotate 1 -flop 1 $i/luma13.pgm - ./luma -w $w -h $h -bpp $bpp -bands 12 -rband 1 -rotate 1 -vmirror 1 $i/luma14.pgm - ./luma -w $w -h $h -bpp $bpp -offset 32768 -dmirror 1 -hmirror 1 $i/luma15.pgm - ./luma -w $w -h $h -bpp $bpp -type 1 $i/luma16.pgm - ./luma -w $w -h $h -bpp $bpp -type 1 -bands 2 -rband 1 $i/luma17.pgm - ./luma -w $w -h $h -bpp $bpp -type 2 $i/luma18.pgm - ./luma -w $w -h $h -bpp $bpp -type 2 -quart 1 $i/luma19.pgm - ./luma -w $w -h $h -bpp $bpp -type 2 -quart 1 -flip 1 $i/luma20.pgm - ./luma -w $w -h $h -bpp $bpp -type 2 -quart 1 -bands 2 $i/luma21.pgm - ./luma -w $w -h $h -bpp $bpp -type 3 $i/luma22.pgm - - if [ -f .compress ] - then - for f in $i/*.pgm - do - convert $f $f.png - rm -f $f - done - fi -done - -touch .executed - diff --git a/src/modules/lumas/luma.c b/src/modules/lumas/luma.c deleted file mode 100644 index a4fbfafde..000000000 --- a/src/modules/lumas/luma.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * luma.c -- image generator for transition_luma - * Copyright (C) 2003-2019 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 -#include -#include - -int main( int argc, char **argv ) -{ - int arg = 1; - int bpp = 8; - - struct mlt_luma_map_s self; - uint16_t *image = NULL; - const char *filename = NULL; - - mlt_luma_map_init( &self ); - - for ( arg = 1; arg < argc; arg ++ ) - { - if ( !strcmp( argv[ arg ], "-bpp" ) ) - bpp = atoi( argv[ ++ arg ] ); - else if ( !strcmp( argv[ arg ], "-type" ) ) - self.type = atoi( argv[ ++ arg ] ); - else if ( !strcmp( argv[ arg ], "-w" ) ) - { - int tmp = atoi( argv[ ++ arg ] ); - // TODO: is there an upper bound? - if ( tmp ) - self.w = tmp; - else - return 1; - } - else if ( !strcmp( argv[ arg ], "-h" ) ) - { - int tmp = atoi( argv[ ++ arg ] ); - // TODO: is there an upper bound? - if ( tmp ) - self.h = tmp; - else return 1; - } - else if ( !strcmp( argv[ arg ], "-bands" ) ) - { - int tmp = atoi( argv[ ++ arg ] ); - // TODO: is there an upper bound? - if ( tmp >= 0 ) - self.bands = tmp; - else - return 1; - } - else if ( !strcmp( argv[ arg ], "-rband" ) ) - self.rband = atoi( argv[ ++ arg ] ); - else if ( !strcmp( argv[ arg ], "-hmirror" ) ) - self.hmirror = atoi( argv[ ++ arg ] ); - else if ( !strcmp( argv[ arg ], "-vmirror" ) ) - self.vmirror = atoi( argv[ ++ arg ] ); - else if ( !strcmp( argv[ arg ], "-dmirror" ) ) - self.dmirror = atoi( argv[ ++ arg ] ); - else if ( !strcmp( argv[ arg ], "-offset" ) ) - self.offset = atoi( argv[ ++ arg ] ); - else if ( !strcmp( argv[ arg ], "-invert" ) ) - self.invert = atoi( argv[ ++ arg ] ); - else if ( !strcmp( argv[ arg ], "-flip" ) ) - self.flip = atoi( argv[ ++ arg ] ); - else if ( !strcmp( argv[ arg ], "-flop" ) ) - self.flop = atoi( argv[ ++ arg ] ); - else if ( !strcmp( argv[ arg ], "-pflip" ) ) - self.pflip = atoi( argv[ ++ arg ] ); - else if ( !strcmp( argv[ arg ], "-pflop" ) ) - self.pflop = atoi( argv[ ++ arg ] ); - else if ( !strcmp( argv[ arg ], "-quart" ) ) - self.quart = atoi( argv[ ++ arg ] ); - else if ( !strcmp( argv[ arg ], "-rotate" ) ) - self.rotate = atoi( argv[ ++ arg ] ); - else - filename = argv[arg]; - } - - if ( bpp != 8 && bpp != 16 ) - { - fprintf( stderr, "Invalid bpp %d\n", bpp ); - return 1; - } - - mlt_pool_init(); - image = mlt_luma_map_render( &self ); - - if ( bpp == 16 ) - { - uint16_t *end = image + self.w * self.h; - uint16_t *p = image; - uint8_t *q = ( uint8_t * )image; - while ( p < end ) - { - *p ++ = ( *q << 8 ) + *( q + 1 ); - q += 2; - } - if (filename) { - FILE *f = fopen(filename, "wb"); - if (f) { - fprintf(f, "P5\x0a" ); - fprintf(f, "%d %d\x0a", self.w, self.h ); - fprintf(f, "65535\x0a" ); - fwrite( image, self.w * self.h * sizeof( uint16_t ), 1, f ); - fclose(f); - } - } else { - printf( "P5\n" ); - printf( "%d %d\n", self.w, self.h ); - printf( "65535\n" ); - fwrite( image, self.w * self.h * sizeof( uint16_t ), 1, stdout ); - } - } - else - { - uint16_t *end = image + self.w * self.h; - uint16_t *p = image; - uint8_t *q = ( uint8_t * )image; - while ( p < end ) - *q ++ = ( uint8_t )( *p ++ >> 8 ); - printf( "P5\n" ); - printf( "%d %d\n", self.w, self.h ); - printf( "255\n" ); - fwrite( image, self.w * self.h, 1, stdout ); - } - - return 0; -} - diff --git a/src/modules/motion_est/CMakeLists.txt b/src/modules/motion_est/CMakeLists.txt deleted file mode 100644 index 89d16ad4c..000000000 --- a/src/modules/motion_est/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -add_library(mltmotion_est MODULE - arrow_code.c - factory.c - filter_autotrack_rectangle.c - filter_crop_detect.c - filter_motion_est.c - filter_vismv.c - producer_slowmotion.c -) - -target_link_libraries(mltmotion_est mlt m) - -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltmotion_est PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) - -install(TARGETS mltmotion_est LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) - -install(FILES - filter_autotrack_rectangle.yml - filter_motion_est.yml - filter_vismv.yml - producer_slowmotion.yml - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/motion_est -) diff --git a/src/modules/motion_est/Makefile b/src/modules/motion_est/Makefile deleted file mode 100644 index 0d142750e..000000000 --- a/src/modules/motion_est/Makefile +++ /dev/null @@ -1,57 +0,0 @@ -CFLAGS += -I../.. - -LDFLAGS += -L../../framework -lmlt -lm - -include ../../../config.mak - -TARGET = ../libmltmotion_est$(LIBSUF) - -OBJS = factory.o \ - filter_motion_est.o \ - filter_crop_detect.o \ - filter_autotrack_rectangle.o \ - arrow_code.o \ - filter_vismv.o \ - producer_slowmotion.o - -SRCS := $(OBJS:.o=.c) - -all: $(TARGET) - -$(TARGET): $(OBJS) - $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) - -depend: $(SRCS) - $(CC) -MM $(CFLAGS) $^ 1>.depend - -distclean: clean - rm -f .depend - -clean: - rm -f $(OBJS) $(TARGET) - -install: all - install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" - install -d "$(DESTDIR)$(mltdatadir)/motion_est" - install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/motion_est" - -test: $(TARGET) - ~/mlt-devel/mlt/src/melt/melt -filter motion_est -filter vismv -filter benchmark -consumer sdl rescale=none real_time=0 audio_off=1 silent=1 /media/cdrecorder/BBC.The.Private.Life.Of.Plants.Pt5.Living.Together.DivX505.AC3.www.MVGroup.org.uk.avi in=50000 - -hist: $(TARGET) - ~/mlt-devel/mlt/src/melt/melt -filter motion_est -filter histogram -consumer sdl rescale=none real_time=0 audio_off=1 silent=1 /media/cdrecorder/BBC.The.Private.Life.Of.Plants.Pt5.Living.Together.DivX505.AC3.www.MVGroup.org.uk.avi in=40000 - - -test2: $(TARGET) - melt colour:black -filter watermark:"+mello.txt" composite.geometry="0/0:10%x10%;99=90%/90%" composite.out=99 -filter crop_detect -filter motion_est -filter vismv - -realtime: $(TARGET) - ~/mlt-devel/mlt/src/melt/melt -filter motion_est -filter vismv -consumer sdl rescale=none /media/cdrecorder/BBC.The.Private.Life.Of.Plants.Pt5.Living.Together.DivX505.AC3.www.MVGroup.org.uk.avi in=30000 - -testhist: $(TARGET) - ~/mlt-devel/mlt/src/melt/melt -consumer sdl rescale=none silent=1 -filter motion_est -filter histogram -filter vismv /media/cdrecorder/BBC.The.Private.Life.Of.Plants.Pt5.Living.Together.DivX505.AC3.www.MVGroup.org.uk.avi in=10000 - - -ifneq ($(wildcard .depend),) -include .depend -endif diff --git a/src/modules/motion_est/README b/src/modules/motion_est/README deleted file mode 100644 index ee7de1770..000000000 --- a/src/modules/motion_est/README +++ /dev/null @@ -1,97 +0,0 @@ -INTRO: - -This module is designed to provide application agnostic motion estimation. -I wrote it from scratch because I found the other Open Source code to be -limited by their difficulty of reuse. - - -COMPILE: - -To compile this module, you must supply these options to the root configure script: - ---enable-gpl --enable-motion-est - - -EXAMPLES: - -Estimate the motion: - - > melt -filter motion_est - -To display the motion vectors as pretty arrows: - - > melt -filter motion_est -filter vismv - -If your using a movie file that contains a crop, you will get better results with this: - - > melt -filter crop_detect -filter motion_est -filter vismv - -If your computer is unable to do the above examples in real time, try this: - - > melt -filter motion_est -filter vismv -consumer melt real_time=0 - -If you'd like to see the motion vectors without the median denoising function, do this: - - > melt -filter motion_est denoise=0 -filter vismv - -To reconstruct each frame by applying the motion to the previous frame: - - > melt -filter motion_est show_reconstruction=1 - -To compare the reconstructed frame and the real frame (while paused): - - > melt -filter motion_est show_reconstruction=1 toggle_when_paused=1 - -To show the difference (residual) between the reconstructed frame the real frame: - - > melt -filter motion_est show_residual=1 - -To automatically track an object in the frame, try this: - - > melt -filter autotrack_rectangle:X,Y:WxH debug=1 - -(Where X,Y is the origin of the rectangle indexed from upper left and WxH is the dimensions of the rectangle.) - -To obscure that same object in the frame, try this: - - > melt -filter autotrack_rectangle:X,Y:WxH obscure=1 - -There is now a slow motion producer that does interpolation based on the motion vectors: - - > melt slowmotion: _speed=0.1 method=1 debug=1 - -NOTES (and deficiencies): - -1. Ignore shot change detection when your using the autotrack_rectangle filter. - -2. Don't assume motion vectors displayed while stepping backwards and forward are that same vectors - that would be calculated while playing the footage from start to finish, nonstop. Stepping forward - should be fine after a few frames, however. - -3. SSE instructions are lazily assumed. MMX, Altivec, and SIMD-less would be good too. - -4. Motion estimation is only performed in the luma color space. - -5. Motion vectors should have sub-pixel accuracy. - -6. Motion vectors are not serializable yet. - -7. A diligent test suite is needed. (show_reconstruction & show_residual are a start) - -8. Multithreaded code will see HUGE benefits on multi-CPU systems. Donations of a multi-core cpu or a - multi-cpu system to the author will encourage development. - -9. Macroblock sizes are not dynamic (Though settable at runtime.) - -10. Notes (5), (7), and (9) would go a long ways to making this code suitable for a modern video encoder. - -11. Shot change works well but arbitrarily chosen thresholds need to be tuned. - -12. Given the documentation of other motion estimation code bases, I will GLADLY clarify and - document any piece of code upon request. - -13. Considerable effort has been put into the speed. I usually experience 10ms or less per frame for PAL on 2.8GHZ p4. - -Zachary Drew -drew0054@tc.umn.edu - diff --git a/src/modules/motion_est/arrow_code.c b/src/modules/motion_est/arrow_code.c deleted file mode 100644 index 69a507dca..000000000 --- a/src/modules/motion_est/arrow_code.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * /brief Draw arrows - * /author Zachary Drew, Copyright 2004 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include "arrow_code.h" - -#include -#include -#include -#include - -#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) -#define ABS(a) ((a) >= 0 ? (a) : (-(a))) - - -static int w; -static int h; -static int xstride; -static int ystride; -static mlt_image_format format; - -int init_arrows( mlt_image_format *image_format, int width, int height ) -{ - w = width; - h = height; - format = *image_format; - switch( *image_format ) { - case mlt_image_yuv422: - xstride = 2; - ystride = xstride * w; - break; - default: - // I don't know - return 0; - } - return 1; - -} - -// ffmpeg borrowed -static inline int clip(int a, int amin, int amax) -{ - if (a < amin) - return amin; - else if (a > amax) - return amax; - else - return a; -} - - -/** - * draws an line from (ex, ey) -> (sx, sy). - * Credits: modified from ffmpeg project - * @param ystride stride/linesize of the image - * @param xstride stride/element size of the image - * @param color color of the arrow - */ -void draw_line(uint8_t *buf, int sx, int sy, int ex, int ey, int color) -{ - int t, x, y, fr, f; - - - sx= clip(sx, 0, w-1); - sy= clip(sy, 0, h-1); - ex= clip(ex, 0, w-1); - ey= clip(ey, 0, h-1); - - buf[sy*ystride + sx*xstride]+= color; - - if(ABS(ex - sx) > ABS(ey - sy)){ - if(sx > ex){ - t=sx; sx=ex; ex=t; - t=sy; sy=ey; ey=t; - } - buf+= sx*xstride + sy*ystride; - ex-= sx; - f= ((ey-sy)<<16)/ex; - for(x= 0; x <= ex; x++){ - y = (x*f)>>16; - fr= (x*f)&0xFFFF; - buf[ y *ystride + x*xstride]+= (color*(0x10000-fr))>>16; - buf[(y+1)*ystride + x*xstride]+= (color* fr )>>16; - } - }else{ - if(sy > ey){ - t=sx; sx=ex; ex=t; - t=sy; sy=ey; ey=t; - } - buf+= sx*xstride + sy*ystride; - ey-= sy; - if(ey) f= ((ex-sx)<<16)/ey; - else f= 0; - for(y= 0; y <= ey; y++){ - x = (y*f)>>16; - fr= (y*f)&0xFFFF; - buf[y*ystride + x *xstride]+= (color*(0x10000-fr))>>16;; - buf[y*ystride + (x+1)*xstride]+= (color* fr )>>16;; - } - } -} - -void draw_rectangle_fill(uint8_t *buf, int x, int y, int w, int h, int color) -{ - int i,j; - for ( i = 0; i < w; i++ ) - for ( j = 0; j < h; j++ ) - buf[ (y+j)*ystride + (x+i)*xstride] = color; -} - -void draw_rectangle_outline(uint8_t *buf, int x, int y, int w, int h, int color) -{ - int i,j; - for ( i = 0; i < w; i++ ) { - buf[ y*ystride + (x+i)*xstride ] += color; - buf[ (y+h)*ystride + (x+i)*xstride ] += color; - } - for ( j = 1; j < h+1; j++ ) { - buf[ (y+j)*ystride + x*xstride ] += color; - buf[ (y+j)*ystride + (x+w)*xstride ] += color; - } -} -/** - * draws an arrow from (ex, ey) -> (sx, sy). - * Credits: modified from ffmpeg project - * @param stride stride/linesize of the image - * @param color color of the arrow - */ -void draw_arrow(uint8_t *buf, int sx, int sy, int ex, int ey, int color){ - - int dx,dy; - dx= ex - sx; - dy= ey - sy; - - if(dx*dx + dy*dy > 3*3){ - int rx= dx + dy; - int ry= -dx + dy; - int length= sqrt((rx*rx + ry*ry)<<8); - - rx= ROUNDED_DIV(rx*3<<4, length); - ry= ROUNDED_DIV(ry*3<<4, length); - - draw_line(buf, sx, sy, sx + rx, sy + ry, color); - draw_line(buf, sx, sy, sx - ry, sy + rx, color); - } - draw_line(buf, sx, sy, ex, ey, color); -} diff --git a/src/modules/motion_est/arrow_code.h b/src/modules/motion_est/arrow_code.h deleted file mode 100644 index 7012e0d4e..000000000 --- a/src/modules/motion_est/arrow_code.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * file: arrow_code.h - * - * /brief Misc functions to draw arrows - * /author Zachary Drew, Copyright 2004 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -extern int init_arrows( mlt_image_format *image_format, int width, int height ); -extern void draw_line(uint8_t *buf, int sx, int sy, int ex, int ey, int color); -extern void draw_arrow(uint8_t *buf, int sx, int sy, int ex, int ey, int color); -extern void draw_rectangle_fill(uint8_t *buf, int x, int y, int w, int h, int color); -extern void draw_rectangle_outline(uint8_t *buf, int x, int y, int w, int h, int color); diff --git a/src/modules/motion_est/factory.c b/src/modules/motion_est/factory.c deleted file mode 100644 index d234b9788..000000000 --- a/src/modules/motion_est/factory.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include - -extern mlt_filter filter_motion_est_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -extern mlt_filter filter_vismv_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -extern mlt_filter filter_crop_detect_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -extern mlt_filter filter_autotrack_rectangle_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -extern mlt_producer producer_slowmotion_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/motion_est/%s", mlt_environment( "MLT_DATA" ), (char*) data ); - return mlt_properties_parse_yaml( file ); -} - -MLT_REPOSITORY -{ - MLT_REGISTER( filter_type, "motion_est", filter_motion_est_init ); - MLT_REGISTER( filter_type, "vismv", filter_vismv_init ); - MLT_REGISTER( filter_type, "crop_detect", filter_crop_detect_init ); - MLT_REGISTER( filter_type, "autotrack_rectangle", filter_autotrack_rectangle_init ); - MLT_REGISTER( producer_type, "slowmotion", producer_slowmotion_init ); - - MLT_REGISTER_METADATA( filter_type, "motion_est", metadata, "filter_motion_est.yml" ); - MLT_REGISTER_METADATA( filter_type, "vismv", metadata, "filter_vismv.yml" ); - MLT_REGISTER_METADATA( filter_type, "crop_detect", metadata, "filter_crop_detect.yml" ); - MLT_REGISTER_METADATA( filter_type, "autotrack_rectangle", metadata, "filter_autotrack_rectangle.yml" ); - MLT_REGISTER_METADATA( producer_type, "slowmotion", metadata, "producer_slowmotion.yml" ); -} diff --git a/src/modules/motion_est/filter_autotrack_rectangle.c b/src/modules/motion_est/filter_autotrack_rectangle.c deleted file mode 100644 index cf82c5059..000000000 --- a/src/modules/motion_est/filter_autotrack_rectangle.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * filter_autotrack_rectangle.c - * - * /brief - * /author Zachary Drew, Copyright 2005 - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "filter_motion_est.h" -#include "arrow_code.h" - -#include - -#include -#include -#include -#include - -#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) -#define ABS(a) ((a) >= 0 ? (a) : (-(a))) - -void caculate_motion( struct motion_vector_s *vectors, - mlt_geometry_item boundry, - int macroblock_width, - int macroblock_height, - int mv_buffer_width, - int method, - int width, - int height ) -{ - - - // translate pixel units (from bounds) to macroblock units - // make sure whole macroblock stay within bounds - int left_mb = ( boundry->x + macroblock_width - 1 ) / macroblock_width; - int top_mb = ( boundry->y + macroblock_height - 1 ) / macroblock_height; - int right_mb = ( boundry->x + boundry->w ) / macroblock_width - 1; - int bottom_mb = ( boundry->y + boundry->h ) / macroblock_height - 1; - - int i, j, n = 0; - - int average_x = 0, average_y = 0; - - #define CURRENT ( vectors + j*mv_buffer_width + i ) - - for( i = left_mb; i <= right_mb; i++ ){ - for( j = top_mb; j <= bottom_mb; j++ ) - { - n++; - average_x += CURRENT->dx; - average_y += CURRENT->dy; - } - } - - if ( n == 0 ) return; - - average_x /= n; - average_y /= n; - - n = 0; - int average2_x = 0, average2_y = 0; - for( i = left_mb; i <= right_mb; i++ ){ - for( j = top_mb; j <= bottom_mb; j++ ){ - - if( ABS(CURRENT->dx - average_x) < 3 && - ABS(CURRENT->dy - average_y) < 3 ) - { - n++; - average2_x += CURRENT->dx; - average2_y += CURRENT->dy; - } - } - } - - if ( n == 0 ) return; - - boundry->x -= (double)average2_x / (double)n; - boundry->y -= (double)average2_y / (double)n; - - if ( boundry->x < 0 ) - boundry->x = 0; - - if ( boundry->y < 0 ) - boundry->y = 0; - - if ( boundry->x + boundry->w > width ) - boundry->x = width - boundry->w; - - if ( boundry->y + boundry->h > height ) - boundry->y = height - boundry->h; -} - -// Image stack(able) method -static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) -{ - - // Get the filter object - mlt_filter filter = mlt_frame_pop_service( frame ); - - // Get the filter's property object - mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter); - - // Get the frame properties - mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame); - - // Get the frame position - mlt_position position = mlt_filter_get_position( filter, frame ); - - mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter)); - - // Disable consumer scaling - if (profile && profile->width && profile->height) { - *width = profile->width; - *height = profile->height; - } - - // Get the new image - int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); - - if( error != 0 ) - mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle", stderr ); - - mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); - - // Get the geometry object - mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); - - // Get the current geometry item - struct mlt_geometry_item_s boundry; - mlt_geometry_fetch(geometry, &boundry, position); - - // Get the motion vectors - struct motion_vector_s *vectors = mlt_properties_get_data( frame_properties, "motion_est.vectors", NULL ); - - // Cleanse the geometry item - boundry.w = boundry.x < 0 ? boundry.w + boundry.x : boundry.w; - boundry.h = boundry.y < 0 ? boundry.h + boundry.y : boundry.h; - boundry.x = boundry.x < 0 ? 0 : boundry.x; - boundry.y = boundry.y < 0 ? 0 : boundry.y; - boundry.w = boundry.w < 0 ? 0 : boundry.w; - boundry.h = boundry.h < 0 ? 0 : boundry.h; - - // How did the rectangle move? - if( vectors != NULL && - boundry.key != 1 ) // Paused? - { - - int method = mlt_properties_get_int( filter_properties, "method" ); - - // Get the size of macroblocks in pixel units - int macroblock_height = mlt_properties_get_int( frame_properties, "motion_est.macroblock_height" ); - int macroblock_width = mlt_properties_get_int( frame_properties, "motion_est.macroblock_width" ); - int mv_buffer_width = *width / macroblock_width; - - caculate_motion( vectors, &boundry, macroblock_width, macroblock_height, mv_buffer_width, method, *width, *height ); - - - // Make the geometry object a real boy - boundry.key = 1; - boundry.f[0] = 1; - boundry.f[1] = 1; - boundry.f[2] = 1; - boundry.f[3] = 1; - boundry.f[4] = 1; - mlt_geometry_insert(geometry, &boundry); - mlt_geometry_interpolate(geometry); - } - - mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); - - if( mlt_properties_get_int( filter_properties, "debug" ) == 1 ) - { - init_arrows( format, *width, *height ); - draw_rectangle_outline(*image, boundry.x, boundry.y, boundry.w, boundry.h, 100); - } - - if( mlt_properties_get_int( filter_properties, "_serialize" ) == 1 ) - { - // Add the vector change to the list - mlt_geometry key_frames = mlt_properties_get_data( filter_properties, "motion_vector_list", NULL ); - if ( !key_frames ) - { - key_frames = mlt_geometry_init(); - mlt_properties_set_data( filter_properties, "motion_vector_list", key_frames, 0, - (mlt_destructor) mlt_geometry_close, (mlt_serialiser) mlt_geometry_serialise ); - if ( key_frames ) - mlt_geometry_set_length( key_frames, mlt_filter_get_length2( filter, frame ) ); - } - if ( key_frames ) - { - struct mlt_geometry_item_s item; - item.frame = (int) mlt_frame_get_position( frame ); - item.key = 1; - item.x = boundry.x; - item.y = boundry.y; - item.w = boundry.w; - item.h = boundry.h; - item.mix = 0; - item.f[0] = item.f[1] = item.f[2] = item.f[3] = 1; - item.f[4] = 0; - mlt_geometry_insert( key_frames, &item ); - } - } - - if( mlt_properties_get_int( filter_properties, "obscure" ) == 1 ) - { - mlt_filter obscure = mlt_properties_get_data( filter_properties, "_obscure", NULL ); - - mlt_properties_pass_list( MLT_FILTER_PROPERTIES(obscure), filter_properties, "in, out"); - - // Because filter_obscure needs to be rewritten to use mlt_geometry - char geom[100]; - sprintf( geom, "%d/%d:%dx%d", (int)boundry.x, (int)boundry.y, (int)boundry.w, (int)boundry.h ); - mlt_properties_set( MLT_FILTER_PROPERTIES( obscure ), "start", geom ); - mlt_properties_set( MLT_FILTER_PROPERTIES( obscure ), "end", geom ); - } - - if( mlt_properties_get_int( filter_properties, "collect" ) == 1 ) - { - fprintf( stderr, "%d,%d,%d,%d\n", (int)boundry.x, (int)boundry.y, (int)boundry.w, (int)boundry.h ); - fflush( stdout ); - } - - return error; -} - -static int attach_boundry_to_frame( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) -{ - // Get the filter object - mlt_filter filter = mlt_frame_pop_service( frame ); - - // Get the filter's property object - mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter); - - // Get the frame properties - mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame); - - // Get the frame position - mlt_position position = mlt_filter_get_position( filter, frame ); - - mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter)); - - // Disable consumer scaling - if (profile && profile->width && profile->height) { - *width = profile->width; - *height = profile->height; - } - - mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); - - // Get the geometry object - mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); - if (geometry == NULL) { - mlt_geometry geom = mlt_geometry_init(); - char *arg = mlt_properties_get(filter_properties, "geometry"); - - // Parse the geometry if we have one - mlt_position length = mlt_filter_get_length2( filter, frame ); - mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); - mlt_geometry_parse( geom, arg, length, profile->width, profile->height ); - - // Initialize with the supplied geometry - struct mlt_geometry_item_s item; - mlt_geometry_parse_item( geom, &item, arg ); - - item.frame = 0; - item.key = 1; - item.mix = 100; - - mlt_geometry_insert( geom, &item ); - mlt_geometry_interpolate( geom ); - mlt_properties_set_data( filter_properties, "filter_geometry", geom, 0, (mlt_destructor)mlt_geometry_close, (mlt_serialiser)mlt_geometry_serialise ); - geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); - } - - mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); - - // Get the current geometry item - mlt_geometry_item geometry_item = mlt_pool_alloc( sizeof( struct mlt_geometry_item_s ) ); - mlt_geometry_fetch(geometry, geometry_item, position); - - // Cleanse the geometry item - geometry_item->w = geometry_item->x < 0 ? geometry_item->w + geometry_item->x : geometry_item->w; - geometry_item->h = geometry_item->y < 0 ? geometry_item->h + geometry_item->y : geometry_item->h; - geometry_item->x = geometry_item->x < 0 ? 0 : geometry_item->x; - geometry_item->y = geometry_item->y < 0 ? 0 : geometry_item->y; - geometry_item->w = geometry_item->w < 0 ? 0 : geometry_item->w; - geometry_item->h = geometry_item->h < 0 ? 0 : geometry_item->h; - - mlt_properties_set_data( frame_properties, "bounds", geometry_item, sizeof( struct mlt_geometry_item_s ), mlt_pool_release, NULL ); - - // Get the new image - int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); - - if( error != 0 ) - mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle attach_boundry_to_frame", stderr ); - - return error; -} - -/** Filter processing. -*/ - -static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) -{ - - /* modify the frame with the current geometry */ - mlt_frame_push_service( frame, this); - mlt_frame_push_get_image( frame, attach_boundry_to_frame ); - mlt_properties properties = MLT_FILTER_PROPERTIES( this ); - - /* apply the motion estimation filter */ - mlt_filter motion_est = mlt_properties_get_data( properties, "_motion_est", NULL ); - /* Pass motion_est properties */ - mlt_properties_pass( MLT_FILTER_PROPERTIES( motion_est ), properties, "motion_est." ); - mlt_filter_process( motion_est, frame); - - /* calculate the new geometry based on the motion */ - mlt_frame_push_service( frame, this); - mlt_frame_push_get_image( frame, filter_get_image ); - - - /* visualize the motion vectors */ - if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "debug" ) == 1 ) - { - mlt_filter vismv = mlt_properties_get_data( properties, "_vismv", NULL ); - if( vismv == NULL ) - { - mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); - vismv = mlt_factory_filter( profile, "vismv", NULL ); - mlt_properties_set_data( properties, "_vismv", vismv, 0, (mlt_destructor)mlt_filter_close, NULL ); - } - - mlt_filter_process( vismv, frame ); - } - - if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "obscure" ) == 1 ) - { - mlt_filter obscure = mlt_properties_get_data( properties, "_obscure", NULL ); - if( obscure == NULL ) - { - mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); - obscure = mlt_factory_filter( profile, "obscure", NULL ); - mlt_properties_set_data( properties, "_obscure", obscure, 0, (mlt_destructor)mlt_filter_close, NULL ); - } - - mlt_filter_process( obscure, frame ); - } - - return frame; -} - -/** Constructor for the filter. -*/ - - -mlt_filter filter_autotrack_rectangle_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - mlt_filter this = mlt_filter_new( ); - if ( this != NULL ) - { - this->process = filter_process; - - // Initialize with the supplied geometry if there is one - if( arg != NULL ) - mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "geometry", arg ); - else - mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "geometry", "100/100:100x100" ); - - // create an instance of the motion_est and obscure filter - mlt_filter motion_est = mlt_factory_filter( profile, "motion_est", NULL ); - if( motion_est != NULL ) - mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_motion_est", motion_est, 0, (mlt_destructor)mlt_filter_close, NULL ); - else { - mlt_filter_close( this ); - return NULL; - } - - - } - - return this; -} - -/** This source code will self destruct in 5...4...3... -*/ diff --git a/src/modules/motion_est/filter_autotrack_rectangle.yml b/src/modules/motion_est/filter_autotrack_rectangle.yml deleted file mode 100644 index 273be6518..000000000 --- a/src/modules/motion_est/filter_autotrack_rectangle.yml +++ /dev/null @@ -1,11 +0,0 @@ -schema_version: 0.1 -type: filter -identifier: autotrack_rectangle -title: Autotrack Rectangle (*deprecated*) -version: 1 -copyright: Zachary Drew -creator: Zachary Drew -license: GPLv2 -language: en -tags: - - Video diff --git a/src/modules/motion_est/filter_crop_detect.c b/src/modules/motion_est/filter_crop_detect.c deleted file mode 100644 index d7b709531..000000000 --- a/src/modules/motion_est/filter_crop_detect.c +++ /dev/null @@ -1,247 +0,0 @@ -/** - * /brief Crop Detection filter - * - * /author Zachary Drew, Copyright 2005 - * - * inspired by mplayer's cropdetect filter - * - * Note: The goemetry generated is zero-indexed and is inclusive of the end values - * - * Options: - * -filter crop_detect debug=1 // Visualize crop - * -filter crop_detect frequency=25 // Detect the crop once a second - * -filter crop_detect frequency=0 // Never detect unless the producer changes - * -filter crop_detect thresh=100 // Changes the threshold (default = 25) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#define DEBUG -#define DEFAULT_THRESH 20 - -#include - -#include -#include -#include -#include -#include "arrow_code.h" - -#define ABS(a) ((a) >= 0 ? (a) : (-(a))) - -// Image stack(able) method -static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) -{ - - // Get the filter object and properties - mlt_filter filter = mlt_frame_pop_service( this ); - mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); - mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter)); - - // Disable consumer scaling - if (profile && profile->width && profile->height) { - *width = profile->width; - *height = profile->height; - } - - // Get the new image - int error = mlt_frame_get_image( this, image, format, width, height, 1 ); - - if( error != 0 ) { - mlt_properties_debug( MLT_FRAME_PROPERTIES(this), "error after mlt_frame_get_image()", stderr ); - return error; - } - - // Parameter that describes how often to check for the crop - int frequency = mlt_properties_get_int( properties, "frequency"); - - // Producers may start with blank footage, by default we will skip, oh, 5 frames unless overridden - int skip = mlt_properties_get_int( properties, "skip"); - - mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); - - // The result - mlt_geometry_item bounds = mlt_properties_get_data( properties, "bounds", NULL ); - - // Initialize if needed - if( bounds == NULL ) { - bounds = calloc( 1, sizeof( struct mlt_geometry_item_s ) ); - bounds->w = *width; - bounds->h = *height; - mlt_properties_set_data( properties, "bounds", bounds, sizeof( struct mlt_geometry_item_s ), free, NULL ); - } - - // For periodic detection (with offset of 'skip') - if( frequency == 0 || (int)(mlt_filter_get_position(filter, this)+skip) % frequency != 0) - { - // Inject in stream - mlt_properties_set_data( MLT_FRAME_PROPERTIES(this), "bounds", bounds, sizeof( struct mlt_geometry_item_s ), NULL, NULL ); - - return 0; - } - - - // There is no way to detect a crop for sure, so make up an arbitrary one - int thresh = mlt_properties_get_int( properties, "thresh" ); - - *format = mlt_image_yuv422; - int xstride = 2; - int ystride = 2 * *width; - - int x, y, average_brightness, deviation; // Scratch variables - uint8_t *q; - - // Top crop - for( y = 0; y < *height/2; y++ ) { - bounds->y = y; - average_brightness = 0; - deviation = 0; - q = *image + y*ystride; - for( x = 0; x < *width; x++ ) - average_brightness += q[x*xstride]; - - average_brightness /= *width; - - for( x = 0; x < *width; x++ ) - deviation += abs(average_brightness - q[x*xstride]); - - if( deviation*10 >= thresh * *width ) - break; - } - - // Bottom crop - for( y = *height - 1; y >= *height/2; y-- ) { - bounds->h = y; - average_brightness = 0; - deviation = 0; - q = *image + y*ystride; - for( x = 0; x < *width; x++ ) - average_brightness += q[x*xstride]; - - average_brightness /= *width; - - for( x = 0; x < *width; x++ ) - deviation += abs(average_brightness - q[x*xstride]); - - if( deviation*10 >= thresh * *width) - break; - } - - // Left crop - for( x = 0; x < *width/2; x++ ) { - bounds->x = x; - average_brightness = 0; - deviation = 0; - q = *image + x*xstride; - for( y = 0; y < *height; y++ ) - average_brightness += q[y*ystride]; - - average_brightness /= *height; - - for( y = 0; y < *height; y++ ) - deviation += abs(average_brightness - q[y*ystride]); - - if( deviation*10 >= thresh * *width ) - break; - } - - // Right crop - for( x = *width - 1; x >= *width/2; x-- ) { - bounds->w = x; - average_brightness = 0; - deviation = 0; - q = *image + x*xstride; - for( y = 0; y < *height; y++ ) - average_brightness += q[y*ystride]; - - average_brightness /= *height; - - for( y = 0; y < *height; y++ ) - deviation += abs(average_brightness - q[y*ystride]); - - if( deviation*10 >= thresh * *width ) - break; - } - - /* Debug: Draw arrows to show crop */ - if( mlt_properties_get_int( properties, "debug") == 1 ) - { - init_arrows( format, *width, *height ); - - draw_arrow(*image, bounds->x, *height/2, bounds->x+50, *height/2, 100); - draw_arrow(*image, *width/2, bounds->y, *width/2, bounds->y+50, 100); - draw_arrow(*image, bounds->w, *height/2, bounds->w-50, *height/2, 100); - draw_arrow(*image, *width/2, bounds->h, *width/2, bounds->h-50, 100); - draw_arrow(*image, bounds->x, bounds->y, bounds->x+40, bounds->y+30, 100); - draw_arrow(*image, bounds->x, bounds->h, bounds->x+40, bounds->h-30, 100); - draw_arrow(*image, bounds->w, bounds->y, bounds->w-40, bounds->y+30, 100); - draw_arrow(*image, bounds->w, bounds->h, bounds->w-40, bounds->h-30, 100); - } - - // Convert to width and correct indexing - bounds->w -= bounds->x - 1; - bounds->h -= bounds->y - 1; - - if( mlt_properties_get_int( properties, "debug") == 1 ) - fprintf(stderr, "Top:%f Left:%f Width:%f Height:%f\n", bounds->y, bounds->x, bounds->w, bounds->h); - - /* inject into frame */ - mlt_properties_set_data( MLT_FRAME_PROPERTIES(this), "bounds", bounds, sizeof( struct mlt_geometry_item_s ), NULL, NULL ); - - mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); - - return error; -} - - - -/** Filter processing. -*/ - -static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) -{ - - // Put the filter object somewhere we can find it - mlt_frame_push_service( frame, this); - - // Push the frame filter - mlt_frame_push_get_image( frame, filter_get_image ); - - return frame; -} - -/** Constructor for the filter. -*/ -mlt_filter filter_crop_detect_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - mlt_filter this = mlt_filter_new( ); - if ( this != NULL ) - { - this->process = filter_process; - - /* defaults */ - mlt_properties_set_int( MLT_FILTER_PROPERTIES(this), "frequency", 1); - mlt_properties_set_int( MLT_FILTER_PROPERTIES(this), "thresh", 5); - mlt_properties_set_int( MLT_FILTER_PROPERTIES(this), "clip", 5); - mlt_properties_set_int( MLT_FILTER_PROPERTIES(this), "former_producer_id", -1); - - } - - return this; -} - -/** This source code will self destruct in 5...4...3... -*/ - diff --git a/src/modules/motion_est/filter_motion_est.c b/src/modules/motion_est/filter_motion_est.c deleted file mode 100644 index 7ee71ecec..000000000 --- a/src/modules/motion_est/filter_motion_est.c +++ /dev/null @@ -1,1152 +0,0 @@ -/* - * /brief fast motion estimation filter - * /author Zachary Drew, Copyright 2005 - * - * Currently only uses Gamma data for comparisonon (bug or feature?) - * SSE optimized where available. - * - * Vector orientation: The vector data that is generated for the current frame specifies - * the motion from the previous frame to the current frame. To know how a macroblock - * in the current frame will move in the future, the next frame is needed. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - - -#include "filter_motion_est.h" -#include -#include -#include -#include -#include -#include -#include - -#ifdef USE_SSE -#include "sad_sse.h" -#endif - -#define NDEBUG -#include - -#undef DEBUG -#undef DEBUG_ASM -#undef BENCHMARK -#undef COUNT_COMPARES - -#define DIAMOND_SEARCH 0x0 -#define FULL_SEARCH 0x1 -#define SHIFT 8 -#define ABS(a) ((a) >= 0 ? (a) : (-(a))) - - -struct motion_est_context_s -{ - int initialized; // true if filter has been initialized - -#ifdef COUNT_COMPARES - int compares; -#endif - - /* same as mlt_frame's parameters */ - int width, height; - - /* Operational details */ - int mb_w, mb_h; - int xstride, ystride; - uint8_t *cache_image; // Copy of current frame - uint8_t *former_image; // Copy of former frame - int search_method; - int skip_prediction; - int shot_change; - int limit_x, limit_y; // max x and y of a motion vector - int initial_thresh; - int check_chroma; // if check_chroma == 1 then compare chroma - int denoise; - int previous_msad; - int show_reconstruction; - int toggle_when_paused; - int show_residual; - - /* bounds */ - struct mlt_geometry_item_s bounds; // Current bounds (from filters crop_detect, autotrack rectangle, or other) - - /* bounds in macroblock units; macroblocks are completely contained within the boundry */ - int left_mb, prev_left_mb, right_mb, prev_right_mb; - int top_mb, prev_top_mb, bottom_mb, prev_bottom_mb; - - /* size of our vector buffers */ - int mv_buffer_height, mv_buffer_width, mv_size; - - /* vector buffers */ - int former_vectors_valid; // right || x2 + *w > right ) - w_remains = right - ((*x > x2) ? *x : x2); - - // Origin of macroblock moves above image boundy - if( *y < top || y2 < top ) { - h_remains = *h - top + ((*y < y2) ? *y : y2); - *y += *h - h_remains; - } - // Portion of macroblock moves below image boundry - else if( *y + *h > bottom || y2 + *h > bottom ) - h_remains = bottom - ((*y > y2) ? *y : y2); - - if( w_remains == *w && h_remains == *h ) return penalty; - if( w_remains <= 0 || h_remains <= 0) return 0; // Block is clipped out of existence - penalty = (*w * *h * penalty) - / ( w_remains * h_remains); // Recipricol of the fraction of the block that remains - - assert(*x >= left); assert(x2 + *w - w_remains >= left); - assert(*y >= top); assert(y2 + *h - h_remains >= top); - assert(*x + w_remains <= right); assert(x2 + w_remains <= right); - assert(*y + h_remains <= bottom); assert(y2 + h_remains <= bottom); - - *w = w_remains; // Update the width and height - *h = h_remains; - - return penalty; -} - -/** /brief Reference Sum of Absolute Differences comparison function -* -*/ -static int sad_reference( uint8_t *block1, uint8_t *block2, const int xstride, const int ystride, const int w, const int h ) -{ - int i, j, score = 0; - for ( j = 0; j < h; j++ ){ - for ( i = 0; i < w; i++ ){ - score += ABS( block1[i*xstride] - block2[i*xstride] ); - } - block1 += ystride; - block2 += ystride; - } - - return score; -} - - -/** /brief Abstracted block comparison function -*/ -inline static int block_compare( uint8_t *block1, - uint8_t *block2, - int x, - int y, - int dx, - int dy, - struct motion_est_context_s *c) -{ - -#ifdef COUNT_COMPARES - c->compares++; -#endif - - int score; - - // Default comparison may be overridden by the slower, more capable reference comparison - int (*cmp)(uint8_t *, uint8_t *, int, int, int, int) = c->compare_optimized; - - // vector displacement limited has been exceeded - if( ABS( dx ) >= c->limit_x || ABS( dy ) >= c->limit_y ) - return MAX_MSAD; - - int mb_w = c->mb_w; // Some writeable local copies - int mb_h = c->mb_h; - - // Determine if either macroblock got clipped - int penalty = constrain( &x, &y, &mb_w, &mb_h, dx, dy, 0, c->width, 0, c->height); - - // Some gotchas - if( penalty == 0 ) // Clipped out of existence: Return worst score - return MAX_MSAD; - else if( penalty != 1<compare_reference; - - // Calculate the memory locations of the macroblocks - block1 += x * c->xstride + y * c->ystride; - block2 += (x+dx) * c->xstride + (y+dy) * c->ystride; - - #ifdef DEBUG_ASM - if( penalty == 1<compare_reference( block1, block2, c->xstride, c->ystride, mb_w, mb_h ); - int score2 = c->compare_optimized( block1, block2, c->xstride, c->ystride, mb_w, mb_h ); - if ( score != score2 ) - fprintf(stderr, "Your assembly doesn't work! Reference: %d Asm: %d\n", score, score2); - } - else - #endif - - score = cmp( block1, block2, c->xstride, c->ystride, mb_w, mb_h ); - - return ( score * penalty ) >> SHIFT; // Ditch the extra precision -} - -static inline void check_candidates ( uint8_t *ref, - uint8_t *candidate_base, - const int x, - const int y, - const motion_vector *candidates,// Contains to_x & to_y - const int count, // Number of candidates - const int unique, // Sometimes we know the candidates are unique - motion_vector *result, - struct motion_est_context_s *c ) -{ - int score, i, j; - /* Scan for the best candidate */ - for ( i = 0; i < count; i++ ) - { - // this little dohicky ignores duplicate candidates, if they are possible - if ( unique == 0 ) { - j = 0; - while ( j < i ) - { - if ( candidates[j].dx == candidates[i].dx && - candidates[j].dy == candidates[i].dy ) - goto next_for_loop; - - j++; - } - } - - // Luma - score = block_compare( ref, candidate_base, - x, y, - candidates[i].dx, // from - candidates[i].dy, - c); - - if ( score < result->msad ) { // New minimum - result->dx = candidates[i].dx; - result->dy = candidates[i].dy; - result->msad = score; - } - next_for_loop:; - } -} - -/* /brief Diamond search -* Operates on a single macroblock -*/ -static inline void diamond_search( - uint8_t *ref, //dx; - current.dy = result->dy; - - if ( first == 1 ) // Set the initial pattern - { - candidates[0].dx = result->dx + 1; candidates[0].dy = result->dy + 0; - candidates[1].dx = result->dx + 0; candidates[1].dy = result->dy + 1; - candidates[2].dx = result->dx - 1; candidates[2].dy = result->dy + 0; - candidates[3].dx = result->dx + 0; candidates[3].dy = result->dy - 1; - i = 4; - } - else // Construct the next portion of the search pattern - { - candidates[0].dx = result->dx + best.dx; - candidates[0].dy = result->dy + best.dy; - if (best.dx == former.dx && best.dy == former.dy) { - candidates[1].dx = result->dx + best.dy; - candidates[1].dy = result->dy + best.dx; // Yes, the wires - candidates[2].dx = result->dx - best.dy; // are crossed - candidates[2].dy = result->dy - best.dx; - i = 3; - } else { - candidates[1].dx = result->dx + former.dx; - candidates[1].dy = result->dy + former.dy; - i = 2; - } - - former.dx = best.dx; former.dy = best.dy; // Keep track of new former best - } - - check_candidates ( ref, candidate_base, x, y, candidates, i, 1, result, c ); - - // Which candidate was the best? - best.dx = result->dx - current.dx; - best.dy = result->dy - current.dy; - - // A better candidate was not found - if ( best.dx == 0 && best.dy == 0 ) - return; - - if ( first == 1 ){ - first = 0; - former.dx = best.dx; former.dy = best.dy; // First iteration, sensible value for former.d* - } - } -} - -/* /brief Full (brute) search -* Operates on a single macroblock -*/ -__attribute__((used)) -static void full_search( - uint8_t *ref, //mb_w; i <= c->mb_w; i++ ){ - for( j = -c->mb_h; j <= c->mb_h; j++ ){ - - score = block_compare( ref, candidate_base, - x, - y, - x + i, - y + j, - c); - - if ( score < result->msad ) { - result->dx = i; - result->dy = j; - result->msad = score; - } - } - } -} - -// Macros for pointer calculations -#define CURRENT(i,j) ( c->current_vectors + (j)*c->mv_buffer_width + (i) ) -#define FORMER(i,j) ( c->former_vectors + (j)*c->mv_buffer_width + (i) ) -#define DENOISE(i,j) ( c->denoise_vectors + (j)*c->mv_buffer_width + (i) ) - -int ncompare (const void * a, const void * b) -{ - return ( *(const int*)a - *(const int*)b ); -} - -// motion vector denoising -// for x and y components separately, -// change the vector to be the median value of the 9 adjacent vectors -static void median_denoise( motion_vector *v, struct motion_est_context_s *c ) -{ - int xvalues[9], yvalues[9]; - - int i,j,n; - for( j = c->top_mb; j <= c->bottom_mb; j++ ) - for( i = c->left_mb; i <= c->right_mb; i++ ){ - { - n = 0; - - xvalues[n ] = CURRENT(i,j)->dx; // Center - yvalues[n++] = CURRENT(i,j)->dy; - - if( i > c->left_mb ) // Not in First Column - { - xvalues[n ] = CURRENT(i-1,j)->dx; // Left - yvalues[n++] = CURRENT(i-1,j)->dy; - - if( j > c->top_mb ) { - xvalues[n ] = CURRENT(i-1,j-1)->dx; // Upper Left - yvalues[n++] = CURRENT(i-1,j-1)->dy; - } - - if( j < c->bottom_mb ) { - xvalues[n ] = CURRENT(i-1,j+1)->dx; // Bottom Left - yvalues[n++] = CURRENT(i-1,j+1)->dy; - } - } - if( i < c->right_mb ) // Not in Last Column - { - xvalues[n ] = CURRENT(i+1,j)->dx; // Right - yvalues[n++] = CURRENT(i+1,j)->dy; - - - if( j > c->top_mb ) { - xvalues[n ] = CURRENT(i+1,j-1)->dx; // Upper Right - yvalues[n++] = CURRENT(i+1,j-1)->dy; - } - - if( j < c->bottom_mb ) { - xvalues[n ] = CURRENT(i+1,j+1)->dx; // Bottom Right - yvalues[n++] = CURRENT(i+1,j+1)->dy; - } - } - if( j > c->top_mb ) // Not in First Row - { - xvalues[n ] = CURRENT(i,j-1)->dx; // Top - yvalues[n++] = CURRENT(i,j-1)->dy; - } - - if( j < c->bottom_mb ) // Not in Last Row - { - xvalues[n ] = CURRENT(i,j+1)->dx; // Bottom - yvalues[n++] = CURRENT(i,j+1)->dy; - } - - qsort (xvalues, n, sizeof(int), ncompare); - qsort (yvalues, n, sizeof(int), ncompare); - - if( n % 2 == 1 ) { - DENOISE(i,j)->dx = xvalues[n/2]; - DENOISE(i,j)->dy = yvalues[n/2]; - } - else { - DENOISE(i,j)->dx = (xvalues[n/2] + xvalues[n/2+1])/2; - DENOISE(i,j)->dy = (yvalues[n/2] + yvalues[n/2+1])/2; - } - } - } - - motion_vector *t = c->current_vectors; - c->current_vectors = c->denoise_vectors; - c->denoise_vectors = t; - -} - -// Credits: ffmpeg -// return the median -static inline int median_predictor(int a, int b, int c) { - if ( a > b ){ - if ( c > b ){ - if ( c > a ) b = a; - else b = c; - } - } else { - if ( b > c ){ - if ( c > a ) b = c; - else b = a; - } - } - return b; -} - - -/** /brief Motion search -* -* For each macroblock in the current frame, estimate the block from the last frame that -* matches best. -* -* Vocab: Colocated - the pixel in the previous frame at the current position -* -* Based on enhanced predictive zonal search. [Tourapis 2002] -*/ -static void motion_search( uint8_t *from, //left_mb; i <= c->right_mb; i++ ){ - for( j = c->top_mb; j <= c->bottom_mb; j++ ){ - - here = CURRENT(i,j); - here->valid = 1; - here->color = 100; - here->msad = MAX_MSAD; - count++; - n = 0; - - - /* Stack the predictors [i.e. checked in reverse order] */ - - /* Adjacent to collocated */ - if( c->former_vectors_valid ) - { - // Top of colocated - if( j > c->prev_top_mb ){// && COL_TOP->valid ){ - candidates[n ].dx = FORMER(i,j-1)->dx; - candidates[n++].dy = FORMER(i,j-1)->dy; - } - - // Left of colocated - if( i > c->prev_left_mb ){// && COL_LEFT->valid ){ - candidates[n ].dx = FORMER(i-1,j)->dx; - candidates[n++].dy = FORMER(i-1,j)->dy; - } - - // Right of colocated - if( i < c->prev_right_mb ){// && COL_RIGHT->valid ){ - candidates[n ].dx = FORMER(i+1,j)->dx; - candidates[n++].dy = FORMER(i+1,j)->dy; - } - - // Bottom of colocated - if( j < c->prev_bottom_mb ){// && COL_BOTTOM->valid ){ - candidates[n ].dx = FORMER(i,j+1)->dx; - candidates[n++].dy = FORMER(i,j+1)->dy; - } - - // And finally, colocated - candidates[n ].dx = FORMER(i,j)->dx; - candidates[n++].dy = FORMER(i,j)->dy; - } - - // For macroblocks not in the top row - if ( j > c->top_mb) { - - // Top if ( TOP->valid ) { - candidates[n ].dx = CURRENT(i,j-1)->dx; - candidates[n++].dy = CURRENT(i,j-1)->dy; - //} - - // Top-Right, macroblocks not in the right row - if ( i < c->right_mb ){// && TOP_RIGHT->valid ) { - candidates[n ].dx = CURRENT(i+1,j-1)->dx; - candidates[n++].dy = CURRENT(i+1,j-1)->dy; - } - } - - // Left, Macroblocks not in the left column - if ( i > c->left_mb ){// && LEFT->valid ) { - candidates[n ].dx = CURRENT(i-1,j)->dx; - candidates[n++].dy = CURRENT(i-1,j)->dy; - } - - /* Median predictor vector (median of left, top, and top right adjacent vectors) */ - if ( i > c->left_mb && j > c->top_mb && i < c->right_mb - )//&& LEFT->valid && TOP->valid && TOP_RIGHT->valid ) - { - candidates[n ].dx = median_predictor( CURRENT(i-1,j)->dx, CURRENT(i,j-1)->dx, CURRENT(i+1,j-1)->dx); - candidates[n++].dy = median_predictor( CURRENT(i-1,j)->dy, CURRENT(i,j-1)->dy, CURRENT(i+1,j-1)->dy); - } - - // Zero vector - candidates[n ].dx = 0; - candidates[n++].dy = 0; - - int x = i * c->mb_w; - int y = j * c->mb_h; - check_candidates ( to, from, x, y, candidates, n, 0, here, c ); - - -#ifndef FULLSEARCH - diamond_search( to, from, x, y, here, c); -#else - full_search( to, from, x, y, here, c); -#endif - - assert( x + c->mb_w + here->dx > 0 ); // All macroblocks must have area > 0 - assert( y + c->mb_h + here->dy > 0 ); - assert( x + here->dx < c->width ); - assert( y + here->dy < c->height ); - - } /* End column loop */ - } /* End row loop */ - -#ifdef USE_SSE - asm volatile ( "emms" ); -#endif - -#ifdef COUNT_COMPARES - fprintf(stderr, "%d comparisons per block were made", compares/count); -#endif - return; -} - -void collect_post_statistics( struct motion_est_context_s *c ) { - - c->comparison_average = 0; - c->average_length = 0; - c->average_x = 0; - c->average_y = 0; - - int i, j, count = 0; - - for ( i = c->left_mb; i <= c->right_mb; i++ ){ - for ( j = c->top_mb; j <= c->bottom_mb; j++ ){ - - count++; - c->comparison_average += CURRENT(i,j)->msad; - c->average_x += CURRENT(i,j)->dx; - c->average_y += CURRENT(i,j)->dy; - - - } - } - - if ( count > 0 ) - { - c->comparison_average /= count; - c->average_x /= count; - c->average_y /= count; - c->average_length = sqrt( c->average_x * c->average_x + c->average_y * c->average_y ); - } - -} - -static void init_optimizations( struct motion_est_context_s *c ) -{ - switch(c->mb_w){ -#ifdef USE_SSE - case 4: if(c->mb_h == 4) c->compare_optimized = sad_sse_422_luma_4x4; - else c->compare_optimized = sad_sse_422_luma_4w; - break; - case 8: if(c->mb_h == 8) c->compare_optimized = sad_sse_422_luma_8x8; - else c->compare_optimized = sad_sse_422_luma_8w; - break; - case 16: if(c->mb_h == 16) c->compare_optimized = sad_sse_422_luma_16x16; - else c->compare_optimized = sad_sse_422_luma_16w; - break; - case 32: if(c->mb_h == 32) c->compare_optimized = sad_sse_422_luma_32x32; - else c->compare_optimized = sad_sse_422_luma_32w; - break; - case 64: c->compare_optimized = sad_sse_422_luma_64w; - break; -#endif - default: c->compare_optimized = sad_reference; - break; - } -} - -inline static void set_red(uint8_t *image, struct motion_est_context_s *c) -{ - int n; - for( n = 0; n < c->width * c->height * 2; n+=4 ) - { - image[n] = 79; - image[n+1] = 91; - image[n+2] = 79; - image[n+3] = 237; - } - -} - -static void show_residual( uint8_t *result, struct motion_est_context_s *c ) -{ - int i, j; - int x,y,w,h; - int dx, dy; - int tx,ty; - uint8_t *b, *r; - -// set_red(result,c); - - for( j = c->top_mb; j <= c->bottom_mb; j++ ){ - for( i = c->left_mb; i <= c->right_mb; i++ ){ - - dx = CURRENT(i,j)->dx; - dy = CURRENT(i,j)->dy; - w = c->mb_w; - h = c->mb_h; - x = i * w; - y = j * h; - - // Denoise function caused some blocks to be completely clipped, ignore them - if (constrain( &x, &y, &w, &h, dx, dy, 0, c->width, 0, c->height) == 0 ) - continue; - - for( ty = y; ty < y + h ; ty++ ){ - for( tx = x; tx < x + w ; tx++ ){ - - b = c->former_image + (tx+dx)*c->xstride + (ty+dy)*c->ystride; - r = result + tx*c->xstride + ty*c->ystride; - - r[0] = 16 + ABS( r[0] - b[0] ); - - if( dx % 2 == 0 ) - r[1] = 128 + ABS( r[1] - b[1] ); - else - // FIXME: may exceed boundaries - r[1] = 128 + ABS( r[1] - ( *(b-1) + b[3] ) /2 ); - } - } - } - } -} - -static void show_reconstruction( uint8_t *result, struct motion_est_context_s *c ) -{ - int i, j; - int x,y,w,h; - int dx,dy; - uint8_t *r, *s; - int tx,ty; - - for( i = c->left_mb; i <= c->right_mb; i++ ){ - for( j = c->top_mb; j <= c->bottom_mb; j++ ){ - - dx = CURRENT(i,j)->dx; - dy = CURRENT(i,j)->dy; - w = c->mb_w; - h = c->mb_h; - x = i * w; - y = j * h; - - // Denoise function caused some blocks to be completely clipped, ignore them - if (constrain( &x, &y, &w, &h, dx, dy, 0, c->width, 0, c->height) == 0 ) - continue; - - for( ty = y; ty < y + h ; ty++ ){ - for( tx = x; tx < x + w ; tx++ ){ - - r = result + tx*c->xstride + ty*c->ystride; - s = c->former_image + (tx+dx)*c->xstride + (ty+dy)*c->ystride; - - r[0] = s[0]; - - if( dx % 2 == 0 ) - r[1] = s[1]; - else - // FIXME: may exceed boundaries - r[1] = ( *(s-1) + s[3] ) /2; - } - } - } - } -} - -// Image stack(able) method -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_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter)); - - // Disable consumer scaling - if (profile && profile->width && profile->height) { - *width = profile->width; - *height = profile->height; - } - - mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); - - // Get the motion_est context object - struct motion_est_context_s *c = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), "context", NULL); - - // Get the new image and frame number - *format = mlt_image_yuv422; - int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); - - #ifdef BENCHMARK - struct timeval start; gettimeofday(&start, NULL ); - #endif - - - if( error != 0 ) - mlt_properties_debug( MLT_FRAME_PROPERTIES(frame), "error after mlt_frame_get_image() in motion_est", stderr ); - - c->current_frame_position = mlt_frame_get_position( frame ); - - /* Context Initialization */ - if ( c->initialized == 0 ) { - - // Get the filter properties object - mlt_properties properties = mlt_filter_properties( filter ); - - c->width = *width; - c->height = *height; - - /* Get parameters that may have been overridden */ - if( mlt_properties_get( properties, "macroblock_width") != NULL ) - c->mb_w = mlt_properties_get_int( properties, "macroblock_width"); - - if( mlt_properties_get( properties, "macroblock_height") != NULL ) - c->mb_h = mlt_properties_get_int( properties, "macroblock_height"); - - if( mlt_properties_get( properties, "prediction_thresh") != NULL ) - c->initial_thresh = mlt_properties_get_int( properties, "prediction_thresh" ); - else - c->initial_thresh = c->mb_w * c->mb_h; - - if( mlt_properties_get( properties, "search_method") != NULL ) - c->search_method = mlt_properties_get_int( properties, "search_method"); - - if( mlt_properties_get( properties, "skip_prediction") != NULL ) - c->skip_prediction = mlt_properties_get_int( properties, "skip_prediction"); - - if( mlt_properties_get( properties, "limit_x") != NULL ) - c->limit_x = mlt_properties_get_int( properties, "limit_x"); - - if( mlt_properties_get( properties, "limit_y") != NULL ) - c->limit_y = mlt_properties_get_int( properties, "limit_y"); - - if( mlt_properties_get( properties, "check_chroma" ) != NULL ) - c->check_chroma = mlt_properties_get_int( properties, "check_chroma" ); - - if( mlt_properties_get( properties, "denoise" ) != NULL ) - c->denoise = mlt_properties_get_int( properties, "denoise" ); - - if( mlt_properties_get( properties, "show_reconstruction" ) != NULL ) - c->show_reconstruction = mlt_properties_get_int( properties, "show_reconstruction" ); - - if( mlt_properties_get( properties, "show_residual" ) != NULL ) - c->show_residual = mlt_properties_get_int( properties, "show_residual" ); - - if( mlt_properties_get( properties, "toggle_when_paused" ) != NULL ) - c->toggle_when_paused = mlt_properties_get_int( properties, "toggle_when_paused" ); - - init_optimizations( c ); - - // Calculate the dimensions in macroblock units - c->mv_buffer_width = (*width / c->mb_w); - c->mv_buffer_height = (*height / c->mb_h); - - // Size of the motion vector buffer - c->mv_size = c->mv_buffer_width * c->mv_buffer_height * sizeof(struct motion_vector_s); - - // Allocate the motion vector buffers - c->former_vectors = mlt_pool_alloc( c->mv_size ); - c->current_vectors = mlt_pool_alloc( c->mv_size ); - c->denoise_vectors = mlt_pool_alloc( c->mv_size ); - - // Register motion buffers for destruction - mlt_properties_set_data( properties, "current_motion_vectors", (void *)c->current_vectors, 0, mlt_pool_release, NULL ); - mlt_properties_set_data( properties, "former_motion_vectors", (void *)c->former_vectors, 0, mlt_pool_release, NULL ); - mlt_properties_set_data( properties, "denoise_motion_vectors", (void *)c->denoise_vectors, 0, mlt_pool_release, NULL ); - - c->former_vectors_valid = 0; - memset( c->former_vectors, 0, c->mv_size ); - - c->xstride = 2; - c->ystride = c->xstride * *width; - - // Allocate a cache for the previous frame's image - c->former_image = mlt_pool_alloc( *width * *height * 2 ); - c->cache_image = mlt_pool_alloc( *width * *height * 2 ); - - // Register for destruction - mlt_properties_set_data( properties, "cache_image", (void *)c->cache_image, 0, mlt_pool_release, NULL ); - mlt_properties_set_data( properties, "former_image", (void *)c->former_image, 0, mlt_pool_release, NULL ); - - c->former_frame_position = c->current_frame_position; - c->previous_msad = 0; - - c->initialized = 1; - } - - /* Check to see if somebody else has given us bounds */ - struct mlt_geometry_item_s *bounds = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "bounds", NULL ); - - if ( !bounds ) - { - char *property = mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "bounding" ); - if ( property ) - { - mlt_geometry geometry = mlt_geometry_init( ); - mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) ); - if ( geometry ) - { - mlt_geometry_parse( geometry, property, 0, profile->width, profile->height ); - bounds = calloc( 1, sizeof(*bounds) ); - mlt_properties_set_data( MLT_FILTER_PROPERTIES(filter), "bounds", bounds, sizeof(*bounds), free, NULL ); - mlt_geometry_fetch( geometry, bounds, 0 ); - mlt_geometry_close( geometry ); - } - } - } - - if( bounds != NULL ) { - // translate pixel units (from bounds) to macroblock units - // make sure whole macroblock stays within bounds - c->left_mb = ( bounds->x + c->mb_w - 1 ) / c->mb_w; - c->top_mb = ( bounds->y + c->mb_h - 1 ) / c->mb_h; - c->right_mb = ( bounds->x + bounds->w ) / c->mb_w - 1; - c->bottom_mb = ( bounds->y + bounds->h ) / c->mb_h - 1; - c->bounds.x = bounds->x; - c->bounds.y = bounds->y; - c->bounds.w = bounds->w; - c->bounds.h = bounds->h; - } else { - c->left_mb = c->prev_left_mb = 0; - c->top_mb = c->prev_top_mb = 0; - c->right_mb = c->prev_right_mb = c->mv_buffer_width - 1; // Zero indexed - c->bottom_mb = c->prev_bottom_mb = c->mv_buffer_height - 1; - c->bounds.x = 0; - c->bounds.y = 0; - c->bounds.w = *width; - c->bounds.h = *height; - } - - // If video is advancing, run motion vector algorithm and etc... - if( c->former_frame_position + 1 == c->current_frame_position ) - { - - // Swap the motion vector buffers and reuse allocated memory - struct motion_vector_s *temp = c->current_vectors; - c->current_vectors = c->former_vectors; - c->former_vectors = temp; - - // This is done because filter_vismv doesn't pay attention to frame boundry - memset( c->current_vectors, 0, c->mv_size ); - - // Perform the motion search - motion_search( c->cache_image, *image, c ); - - collect_post_statistics( c ); - - - // Detect shot changes - if( c->comparison_average > 10 * c->mb_w * c->mb_h && - c->comparison_average > c->previous_msad * 2 ) - { - mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); - mlt_log_verbose( MLT_FILTER_SERVICE(filter), "shot change: %d\n", c->comparison_average); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "shot_change", 1); - c->shot_change = 1; - - // Add the shot change to the list - mlt_geometry key_frames = mlt_properties_get_data( properties, "shot_change_list", NULL ); - if ( !key_frames ) - { - key_frames = mlt_geometry_init(); - mlt_properties_set_data( properties, "shot_change_list", key_frames, 0, - (mlt_destructor) mlt_geometry_close, (mlt_serialiser) mlt_geometry_serialise ); - if ( key_frames ) - mlt_geometry_set_length( key_frames, mlt_filter_get_length2( filter, frame ) ); - } - if ( key_frames ) - { - struct mlt_geometry_item_s item; - item.frame = (int) c->current_frame_position; - item.x = c->comparison_average; - item.f[0] = 1; - item.f[1] = item.f[2] = item.f[3] = item.f[4] = 0; - mlt_geometry_insert( key_frames, &item ); - } - } - else { - c->former_vectors_valid = 1; - c->shot_change = 0; - //fprintf(stderr, " - SAD: %d\n", c->comparison_average); - } - - c->previous_msad = c->comparison_average; - - if( c->comparison_average != 0 ) { // If the frame is not a duplicate of the previous frame - - // denoise the vector buffer - if( c->denoise ) - median_denoise( c->current_vectors, c ); - - // Pass the new vector data into the frame - mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "motion_est.vectors", - (void*)c->current_vectors, c->mv_size, NULL, NULL ); - - // Cache the frame's image. Save the old cache. Reuse memory. - // After this block, exactly two unique frames will be cached - uint8_t *timg = c->cache_image; - c->cache_image = c->former_image; - c->former_image = timg; - memcpy( c->cache_image, *image, *width * *height * c->xstride ); - - - } - else { - // Undo the Swap, This fixes the ugliness caused by a duplicate frame - temp = c->current_vectors; - c->current_vectors = c->former_vectors; - c->former_vectors = temp; - mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "motion_est.vectors", - (void*)c->former_vectors, c->mv_size, NULL, NULL ); - } - - - if( c->shot_change == 1) - ; - else if( c->show_reconstruction ) - show_reconstruction( *image, c ); - else if( c->show_residual ) - show_residual( *image, c ); - - } - // paused - else if( c->former_frame_position == c->current_frame_position ) - { - // Pass the old vector data into the frame if it's valid - if( c->former_vectors_valid == 1 ) { - mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "motion_est.vectors", - (void*)c->current_vectors, c->mv_size, NULL, NULL ); - - if( c->shot_change == 1) - ; - else if( c->toggle_when_paused == 1 ) { - if( c->show_reconstruction ) - show_reconstruction( *image, c ); - else if( c->show_residual ) - show_residual( *image, c ); - c->toggle_when_paused = 2; - } - else if( c->toggle_when_paused == 2 ) - c->toggle_when_paused = 1; - else { - if( c->show_reconstruction ) - show_reconstruction( *image, c ); - else if( c->show_residual ) - show_residual( *image, c ); - } - - } - - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "shot_change", c->shot_change); - } - // there was jump in frame number - else { -// fprintf(stderr, "Warning: there was a frame number jumped from %d to %d.\n", c->former_frame_position, c->current_frame_position); - c->former_vectors_valid = 0; - } - - - // Cache our bounding geometry for the next frame's processing - c->prev_left_mb = c->left_mb; - c->prev_top_mb = c->top_mb; - c->prev_right_mb = c->right_mb; - c->prev_bottom_mb = c->bottom_mb; - - // Remember which frame this is - c->former_frame_position = c->current_frame_position; - - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.macroblock_width", c->mb_w ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.macroblock_height", c->mb_h ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.left_mb", c->left_mb ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.right_mb", c->right_mb ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.top_mb", c->top_mb ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.bottom_mb", c->bottom_mb ); - - #ifdef BENCHMARK - struct timeval finish; gettimeofday(&finish, NULL ); int difference = (finish.tv_sec - start.tv_sec) * 1000000 + (finish.tv_usec - start.tv_usec); - fprintf(stderr, " in frame %d:%d usec\n", c->current_frame_position, difference); - #endif - - mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); - - return error; -} - - - -/** filter processing. -*/ - -static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) -{ - - // Keeps tabs on the filter object - mlt_frame_push_service( frame, this); - - // Push the frame filter - mlt_frame_push_get_image( frame, filter_get_image ); - - return frame; -} - -/** Constructor for the filter. -*/ -mlt_filter filter_motion_est_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - mlt_filter this = mlt_filter_new( ); - if ( this != NULL ) - { - // Get the properties object - mlt_properties properties = MLT_FILTER_PROPERTIES( this ); - - // Initialize the motion estimation context - struct motion_est_context_s *context; - context = mlt_pool_alloc( sizeof(struct motion_est_context_s) ); - mlt_properties_set_data( properties, "context", (void *)context, sizeof( struct motion_est_context_s ), - mlt_pool_release, NULL ); - - - // Register the filter - this->process = filter_process; - - /* defaults that may be overridden */ - context->mb_w = 16; - context->mb_h = 16; - context->skip_prediction = 0; - context->limit_x = 64; - context->limit_y = 64; - context->search_method = DIAMOND_SEARCH; // FIXME: not used - context->check_chroma = 0; - context->denoise = 1; - context->show_reconstruction = 0; - context->show_residual = 0; - context->toggle_when_paused = 0; - - /* reference functions that may have optimized versions */ - context->compare_reference = sad_reference; - - // The rest of the buffers will be initialized when the filter is first processed - context->initialized = 0; - } - return this; -} diff --git a/src/modules/motion_est/filter_motion_est.h b/src/modules/motion_est/filter_motion_est.h deleted file mode 100644 index 03775ae12..000000000 --- a/src/modules/motion_est/filter_motion_est.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Perform motion estimation - * Zachary K Drew, Copyright 2004 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _FILTER_MOTION_EST_H_ -#define _FILTER_MOTION_EST_H_ - -#include - -extern mlt_filter filter_motion_est_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); - -#define MAX_MSAD 0xffff - -struct motion_vector_s -{ - int msad; // -#include - -#include -#include -#include -#include - -#define ABS(a) ((a) >= 0 ? (a) : (-(a))) - -static void paint_arrows( uint8_t *image, struct motion_vector_s *vectors, int w, int h, int mb_w, int mb_h ) -{ - int i, j, x, y; - struct motion_vector_s *p; - for( i = 0; i < w/mb_w; i++ ){ - for( j = 0; j < h/mb_h; j++ ){ - x = i*mb_w; - y = j*mb_h; - p = vectors + (w/mb_w)*j + i; - - if ( p->valid == 1 ) { - //draw_rectangle_outline(image, x-1, y-1, mb_w+1, mb_h+1,100); - //x += mb_w/4; - //y += mb_h/4; - //draw_rectangle_outline(image, x + p->dx, y + p->dy, mb_w, mb_h,100); - x += mb_w/2; - y += mb_h/2; - draw_arrow(image, x, y, x + p->dx, y + p->dy, 100); - //draw_rectangle_fill(image, x + p->dx, y + p->dy, mb_w, mb_h, 100); - } - else if ( p->valid == 2 ) { - draw_rectangle_outline(image, x+1, y+1, mb_w-2, mb_h-2,100); - } - else if ( p->valid == 3 ) { - draw_rectangle_fill(image, x-p->dx, y-p->dy, mb_w, mb_h,0); - } - else if ( p->valid == 4 ) { - draw_line(image, x, y, x + 4, y, 100); - draw_line(image, x, y, x, y + 4, 100); - draw_line(image, x + 4, y, x, y + 4, 100); - - draw_line(image, x+mb_w-1, y+mb_h-1, x+mb_w-5, y+mb_h-1, 100); - draw_line(image, x+mb_w-1, y+mb_h-1, x+mb_w-1, y+mb_h-5, 100); - draw_line(image, x+mb_w-5, y+mb_h-1, x+mb_w-1, y+mb_h-5, 100); - } - } - } -} - -// Image stack(able) method -static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) -{ - // Get the frame properties - mlt_properties properties = MLT_FRAME_PROPERTIES(frame); - mlt_filter filter = mlt_frame_pop_service( frame ); - mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter)); - - // Disable consumer scaling - if (profile && profile->width && profile->height) { - *width = profile->width; - *height = profile->height; - } - - // Get the new image - *format = mlt_image_yuv422; - int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); - - if( error != 0 ) - mlt_properties_debug( MLT_FRAME_PROPERTIES(frame), "error after mlt_frame_get_image()", stderr ); - - - // Get the size of macroblocks in pixel units - int macroblock_height = mlt_properties_get_int( properties, "motion_est.macroblock_height" ); - int macroblock_width = mlt_properties_get_int( properties, "motion_est.macroblock_width" ); - - // Get the motion vectors - struct motion_vector_s *current_vectors = mlt_properties_get_data( properties, "motion_est.vectors", NULL ); - - init_arrows( format, *width, *height ); - - if ( mlt_properties_get_int( properties, "shot_change" ) == 1 ) - { - draw_line(*image, 0, 0, *width, *height, 100); - draw_line(*image, 0, *height, *width, 0, 100); - } - if( current_vectors != NULL ) { - paint_arrows( *image, current_vectors, *width, *height, macroblock_width, macroblock_height); - } - - return error; -} - - - -/** Filter processing. -*/ - -static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) -{ - // Push the frame filter - mlt_frame_push_service( frame, this); - mlt_frame_push_get_image( frame, filter_get_image ); - - - return frame; -} - -/** Constructor for the filter. -*/ - - -mlt_filter filter_vismv_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - mlt_filter this = mlt_filter_new( ); - if ( this != NULL ) - { - this->process = filter_process; - - } - - return this; -} - -/** This source code will self destruct in 5...4...3... -*/ - - - - - - - - diff --git a/src/modules/motion_est/filter_vismv.yml b/src/modules/motion_est/filter_vismv.yml deleted file mode 100644 index e0ba65581..000000000 --- a/src/modules/motion_est/filter_vismv.yml +++ /dev/null @@ -1,11 +0,0 @@ -schema_version: 0.1 -type: filter -identifier: vismv -title: Visualize Motion Vectors -version: 1 -copyright: Zachary Drew -creator: Zachary Drew -license: GPLv2 -language: en -tags: - - Video diff --git a/src/modules/motion_est/gpl b/src/modules/motion_est/gpl deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/modules/motion_est/producer_slowmotion.c b/src/modules/motion_est/producer_slowmotion.c deleted file mode 100644 index 160f98917..000000000 --- a/src/modules/motion_est/producer_slowmotion.c +++ /dev/null @@ -1,414 +0,0 @@ -/* - * producer_slowmotion.c -- create subspeed frames - * Author: Zachary Drew - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "filter_motion_est.h" -#include - -#include -#include -#include -#include -#include -#include -#define SHIFT 8 -#define ABS(a) ((a) >= 0 ? (a) : (-(a))) - -// This is used to constrains pixel operations between two blocks to be within the image boundry -inline static int constrain( int *x, int *y, int *w, int *h, - const int dx, const int dy, - const int left, const int right, - const int top, const int bottom) -{ - uint32_t penalty = 1 << SHIFT; // Retain a few extra bits of precision - int x2 = *x + dx; - int y2 = *y + dy; - int w_remains = *w; - int h_remains = *h; - - // Origin of macroblock moves left of image boundy - if( *x < left || x2 < left ) { - w_remains = *w - left + ((*x < x2) ? *x : x2); - *x += *w - w_remains; - } - // Portion of macroblock moves right of image boundry - else if( *x + *w > right || x2 + *w > right ) - w_remains = right - ((*x > x2) ? *x : x2); - - // Origin of macroblock moves above image boundy - if( *y < top || y2 < top ) { - h_remains = *h - top + ((*y < y2) ? *y : y2); - *y += *h - h_remains; - } - // Portion of macroblock moves below image boundry - else if( *y + *h > bottom || y2 + *h > bottom ) - h_remains = bottom - ((*y > y2) ? *y : y2); - - if( w_remains == *w && h_remains == *h ) return penalty; - if( w_remains <= 0 || h_remains <= 0) return 0; // Block is clipped out of existence - penalty = (*w * *h * penalty) - / ( w_remains * h_remains); // Recipricol of the fraction of the block that remains - - *w = w_remains; // Update the width and height - *h = h_remains; - - return penalty; -} - -static void motion_interpolate( uint8_t *first_image, uint8_t *second_image, uint8_t *output, - int top_mb, int bottom_mb, int left_mb, int right_mb, - int mb_w, int mb_h, - int width, int height, - int xstride, int ystride, - double scale, - motion_vector *vectors ) -{ - assert ( scale >= 0.0 && scale <= 1.0 ); - - int i, j; - int x,y,w,h; - int dx, dy; - int scaled_dx, scaled_dy; - int tx,ty; - uint8_t *f,*s,*r; - motion_vector *here; - int mv_width = width / mb_w; - - for( j = top_mb; j <= bottom_mb; j++ ){ - for( i = left_mb; i <= right_mb; i++ ){ - - here = vectors + j*mv_width + i; - scaled_dx = (1.0 - scale) * (double)here->dx; - scaled_dy = (1.0 - scale) * (double)here->dy; - dx = here->dx; - dy = here->dy; - w = mb_w; h = mb_h; - x = i * w; y = j * h; - - // Denoise function caused some blocks to be completely clipped, ignore them - if (constrain( &x, &y, &w, &h, dx, dy, 0, width, 0, height) == 0 ) - continue; - - for( ty = y; ty < y + h ; ty++ ){ - for( tx = x; tx < x + w ; tx++ ){ - - f = first_image + (tx + dx )*xstride + (ty + dy )*ystride; - s = second_image + (tx )*xstride + (ty )*ystride; - r = output + (tx+scaled_dx)*xstride + (ty+scaled_dy)*ystride; -/* - if( ABS(f[0] - s[0]) > 3 * here->msad / (mb_w * mb_h * 2) ) - { - r[0] = f[0]; - r[1] = f[1]; - } - - else - { - -*/ - r[0] = ( 1.0 - scale ) * (double)f[0] + scale * (double)s[0]; - - if( dx % 2 == 0 ) - { - if( scaled_dx % 2 == 0 ) - r[1] = ( 1.0 - scale ) * (double)f[1] + scale * (double) s[1]; - else - *(r-1) = ( 1.0 - scale ) * (double)f[1] + scale * (double) s[1]; - } - else - { - if( scaled_dx %2 == 0 ) - // FIXME: may exceed boundaries - r[1] = ( 1.0 - scale ) * ( (double)(*(f-1) + (double)f[3]) / 2.0 ) + scale * (double) s[1]; - else - // FIXME: may exceed boundaries - *(r-1) = ( 1.0 - scale ) * ( (double)(*(f-1) + (double)f[3]) / 2.0 ) + scale * (double) s[1]; - } -// } - } - } - } - } -} - -// Image stack(able) method -static int slowmotion_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) -{ - - // Get the filter object and properties - mlt_producer producer = mlt_frame_pop_service( this ); - mlt_frame second_frame = mlt_frame_pop_service( this ); - mlt_frame first_frame = mlt_frame_pop_service( this ); - - mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); - - // Frame properties objects - mlt_properties frame_properties = MLT_FRAME_PROPERTIES( this ); - mlt_properties first_frame_properties = MLT_FRAME_PROPERTIES( first_frame ); - mlt_properties second_frame_properties = MLT_FRAME_PROPERTIES( second_frame ); - - // image stride - *format = mlt_image_yuv422; - int size = *width * *height * 2; - int xstride = 2; - int ystride = 2 * *width; - - uint8_t *output = mlt_properties_get_data( producer_properties, "output_buffer", 0 ); - if( output == NULL ) - { - output = mlt_pool_alloc( size ); - - // Let someone else clean up - mlt_properties_set_data( producer_properties, "output_buffer", output, size, mlt_pool_release, NULL ); - } - - uint8_t *first_image = mlt_properties_get_data( first_frame_properties, "image", NULL ); - uint8_t *second_image = mlt_properties_get_data( second_frame_properties, "image", NULL ); - - // which frames are buffered? - - int error = 0; - - if( first_image == NULL ) - { - error = mlt_frame_get_image( first_frame, &first_image, format, width, height, writable ); - - if( error != 0 ) { - fprintf(stderr, "first_image == NULL get image died\n"); - return error; - } - } - - if( second_image == NULL ) - { - error = mlt_frame_get_image( second_frame, &second_image, format, width, height, writable ); - - if( error != 0 ) { - fprintf(stderr, "second_image == NULL get image died\n"); - return error; - } - } - - // These need to passed onto the frame for other - mlt_properties_pass_list( frame_properties, second_frame_properties, - "motion_est.left_mb, motion_est.right_mb, \ - motion_est.top_mb, motion_est.bottom_mb, \ - motion_est.macroblock_width, motion_est.macroblock_height" ); - - // Pass the pointer to the vectors without serializing - mlt_properties_set_data( frame_properties, "motion_est.vectors", - mlt_properties_get_data( second_frame_properties, "motion_est.vectors", NULL ), - 0, NULL, NULL ); - - - // Start with a base image - memcpy( output, first_image, size ); - - if( mlt_properties_get_int( producer_properties, "method" ) == 1 ) { - - mlt_position first_position = mlt_frame_get_position( first_frame ); - double actual_position = mlt_producer_get_speed( producer ) * (double)mlt_frame_get_position( this ); - double scale = actual_position - first_position; - - motion_interpolate - ( - first_image, second_image, output, - mlt_properties_get_int( second_frame_properties, "motion_est.top_mb" ), - mlt_properties_get_int( second_frame_properties, "motion_est.bottom_mb" ), - mlt_properties_get_int( second_frame_properties, "motion_est.left_mb" ), - mlt_properties_get_int( second_frame_properties, "motion_est.right_mb" ), - mlt_properties_get_int( second_frame_properties, "motion_est.macroblock_width" ), - mlt_properties_get_int( second_frame_properties, "motion_est.macroblock_height" ), - *width, *height, - xstride, ystride, - scale, - mlt_properties_get_data( second_frame_properties, "motion_est.vectors", NULL ) - ); - - if( mlt_properties_get_int( producer_properties, "debug" ) == 1 ) { - mlt_filter watermark = mlt_properties_get_data( producer_properties, "watermark", NULL ); - - if( watermark == NULL ) { - mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); - watermark = mlt_factory_filter( profile, "watermark", NULL ); - mlt_properties_set_data( producer_properties, "watermark", watermark, 0, (mlt_destructor)mlt_filter_close, NULL ); - mlt_producer_attach( producer, watermark ); - } - - mlt_properties wm_properties = MLT_FILTER_PROPERTIES( watermark ); - - char disp[30]; - sprintf(disp, "+%10.2f.txt", actual_position); - mlt_properties_set( wm_properties, "resource", disp ); - - } - - } - - *image = output; - mlt_frame_set_image( this, output, size, NULL ); - - // Make sure that no further scaling is done - mlt_properties_set( frame_properties, "rescale.interps", "none" ); - mlt_properties_set( frame_properties, "scale", "off" ); - - mlt_frame_close( first_frame ); - mlt_frame_close( second_frame ); - - return 0; -} - -static int slowmotion_get_frame( mlt_producer this, mlt_frame_ptr frame, int index ) -{ - if ( !frame ) - return 1; - // Construct a new frame - *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( this ) ); - - mlt_properties properties = MLT_PRODUCER_PROPERTIES(this); - - - if( *frame ) - { - - mlt_frame first_frame = mlt_properties_get_data( properties, "first_frame", NULL ); - mlt_frame second_frame = mlt_properties_get_data( properties, "second_frame", NULL ); - - mlt_position first_position = (first_frame != NULL) ? mlt_frame_get_position( first_frame ) : -1; - mlt_position second_position = (second_frame != NULL) ? mlt_frame_get_position( second_frame ) : -1; - - // Get the real producer - mlt_producer real_producer = mlt_properties_get_data( properties, "producer", NULL ); - - // Our "in" needs to be the same, keep it so - mlt_properties_pass_list( MLT_PRODUCER_PROPERTIES( real_producer ), properties, "in" ); - - // Calculate our positions - double actual_position = mlt_producer_get_speed( this ) * (double)mlt_producer_position( this ); - mlt_position need_first = floor( actual_position ); - mlt_position need_second = need_first + 1; - - if( need_first != first_position ) - { - mlt_frame_close( first_frame ); - first_position = -1; - first_frame = NULL; - } - - if( need_second != second_position) - { - mlt_frame_close( second_frame ); - second_position = -1; - second_frame = NULL; - } - - if( first_frame == NULL ) - { - // Seek the producer to the correct place - mlt_producer_seek( real_producer, need_first ); - - // Get the frame - mlt_service_get_frame( MLT_PRODUCER_SERVICE( real_producer ), &first_frame, index ); - } - - if( second_frame == NULL ) - { - // Seek the producer to the correct place - mlt_producer_seek( real_producer, need_second ); - - // Get the frame - mlt_service_get_frame( MLT_PRODUCER_SERVICE( real_producer ), &second_frame, index ); - } - - // Make sure things are in their place - mlt_properties_set_data( properties, "first_frame", first_frame, 0, NULL, NULL ); - mlt_properties_set_data( properties, "second_frame", second_frame, 0, NULL, NULL ); - - mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_image", 0 ); - - // Stack the producer and producer's get image - mlt_frame_push_service( *frame, first_frame ); - mlt_properties_inc_ref( MLT_FRAME_PROPERTIES( first_frame ) ); - - mlt_frame_push_service( *frame, second_frame ); - mlt_properties_inc_ref( MLT_FRAME_PROPERTIES( second_frame ) ); - - mlt_frame_push_service( *frame, this ); - mlt_frame_push_service( *frame, slowmotion_get_image ); - - // Give the returned frame temporal identity - mlt_frame_set_position( *frame, mlt_producer_position( this ) ); - } - - return 0; -} - -mlt_producer producer_slowmotion_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - mlt_producer this = mlt_producer_new( profile ); - - // Wrap the loader - mlt_producer real_producer = mlt_factory_producer( profile, NULL, arg ); - - // We need to apply the motion estimation filter manually - mlt_filter filter = mlt_factory_filter( profile, "motion_est", NULL ); - - if ( this != NULL && real_producer != NULL && filter != NULL) - { - // attach the motion_est filter to the real producer - mlt_producer_attach( real_producer, filter ); - - // Get the properties of this producer - mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); - - // The loader normalised it for us already - mlt_properties_set_int( properties, "loader_normalised", 1); - - // Store the producer and filter - mlt_properties_set_data( properties, "producer", real_producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); - mlt_properties_set_data( properties, "motion_est", filter, 0, ( mlt_destructor )mlt_filter_close, NULL ); - mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "macroblock_width", 16 ); - mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "macroblock_height", 16 ); - mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "denoise", 0 ); - - // Grap some stuff from the real_producer - mlt_properties_pass_list( properties, MLT_PRODUCER_PROPERTIES( real_producer ), - "in, out, length, resource" ); - - // Since we control the seeking, prevent it from seeking on its own - mlt_producer_set_speed( real_producer, 0 ); - - //mlt_properties_set( properties, "method", "onefield" ); - - // Override the get_frame method - this->get_frame = slowmotion_get_frame; - - } - else - { - if ( this ) - mlt_producer_close( this ); - if ( real_producer ) - mlt_producer_close( real_producer ); - if ( filter ) - mlt_filter_close( filter ); - - this = NULL; - } - return this; -} diff --git a/src/modules/motion_est/producer_slowmotion.yml b/src/modules/motion_est/producer_slowmotion.yml deleted file mode 100644 index 4c0f74472..000000000 --- a/src/modules/motion_est/producer_slowmotion.yml +++ /dev/null @@ -1,11 +0,0 @@ -schema_version: 0.1 -type: producer -identifier: slowmotion -title: Slow Motion (*deprecated*) -version: 1 -copyright: Zachary Drew -creator: Zachary Drew -license: GPLv2 -language: en -tags: - - Video diff --git a/src/modules/motion_est/sad_sse.h b/src/modules/motion_est/sad_sse.h deleted file mode 100644 index 5ec54b41d..000000000 --- a/src/modules/motion_est/sad_sse.h +++ /dev/null @@ -1,429 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include - -#define SAD_SSE_INIT \ - asm volatile ( "pxor %%mm6,%%mm6\n\t" :: );\ - -// Sum two 8x1 pixel blocks -#define SAD_SSE_SUM_8(OFFSET) \ - "movq " #OFFSET "(%0),%%mm0 \n\t"\ - "movq " #OFFSET "(%1),%%mm1 \n\t"\ - "psadbw %%mm1,%%mm0 \n\t"\ - "paddw %%mm0,%%mm6 \n\t"\ - -#define SAD_SSE_FINISH(RESULT) \ - asm volatile( "movd %%mm6,%0" : "=r" (RESULT) : ); - -// Advance by ystride -#define SAD_SSE_NEXTROW \ - "add %2,%0 \n\t"\ - "add %2,%1 \n\t"\ - -// BROKEN! -inline static int sad_sse_4x4( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - SAD_SSE_INIT - #define ROW SAD_SSE_SUM_8(0) SAD_SSE_NEXTROW - asm volatile ( ROW ROW ROW ROW - :: "r" (block1), "r" (block2), "r" ((intptr_t)(ystride))); - - SAD_SSE_FINISH(result) - return result; - #undef ROW - -} - -inline static int sad_sse_8x8( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - SAD_SSE_INIT - #define ROW SAD_SSE_SUM_8(0) SAD_SSE_NEXTROW - asm volatile ( ROW ROW ROW ROW ROW ROW ROW ROW - :: "r" (block1), "r" (block2), "r" ((intptr_t)(ystride))); - - SAD_SSE_FINISH(result) - return result; - #undef ROW - -} - -inline static int sad_sse_16x16( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - SAD_SSE_INIT - #define ROW SAD_SSE_SUM_8(0) SAD_SSE_SUM_8(8) SAD_SSE_NEXTROW - asm volatile ( ROW ROW ROW ROW ROW ROW ROW ROW - ROW ROW ROW ROW ROW ROW ROW ROW - :: "r" (block1), "r" (block2), "r" ((intptr_t)(ystride))); - - SAD_SSE_FINISH(result) - return result; - #undef ROW - -} - -inline static int sad_sse_32x32( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - SAD_SSE_INIT - #define ROW SAD_SSE_SUM_8(0) SAD_SSE_SUM_8(8) SAD_SSE_SUM_8(16) SAD_SSE_SUM_8(24)\ - SAD_SSE_NEXTROW - - asm volatile ( ROW ROW ROW ROW ROW ROW ROW ROW - ROW ROW ROW ROW ROW ROW ROW ROW - ROW ROW ROW ROW ROW ROW ROW ROW - ROW ROW ROW ROW ROW ROW ROW ROW - :: "r" (block1), "r" (block2), "r" ((intptr_t)(ystride))); - - SAD_SSE_FINISH(result) - return result; - #undef ROW - -} -// BROKEN! -inline static int sad_sse_4w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - - SAD_SSE_INIT - - while( h != 0 ) { - asm volatile ( - SAD_SSE_SUM_8(0) - :: "r" (block1), "r" (block2) - ); - - h--; - block1 += ystride; - block2 += ystride; - } - SAD_SSE_FINISH(result) - return result; - -} - -inline static int sad_sse_8w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - - SAD_SSE_INIT - - while( h != 0 ) { - asm volatile ( - SAD_SSE_SUM_8(0) - - :: "r" (block1), "r" (block2) - ); - - h--; - block1 += ystride; - block2 += ystride; - } - SAD_SSE_FINISH(result) - return result; - -} - -inline static int sad_sse_16w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - - SAD_SSE_INIT - - while( h != 0 ) { - asm volatile ( - SAD_SSE_SUM_8(0) - SAD_SSE_SUM_8(8) - - :: "r" (block1), "r" (block2) - ); - - h--; - block1 += ystride; - block2 += ystride; - } - SAD_SSE_FINISH(result) - return result; - -} - -inline static int sad_sse_32w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - - SAD_SSE_INIT - - while( h != 0 ) { - asm volatile ( - SAD_SSE_SUM_8(0) - SAD_SSE_SUM_8(8) - SAD_SSE_SUM_8(16) - SAD_SSE_SUM_8(24) - - :: "r" (block1), "r" (block2) - ); - - h--; - block1 += ystride; - block2 += ystride; - } - SAD_SSE_FINISH(result) - return result; - -} - -inline static int sad_sse_64w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - - SAD_SSE_INIT - - while( h != 0 ) { - asm volatile ( - SAD_SSE_SUM_8(0) - SAD_SSE_SUM_8(8) - SAD_SSE_SUM_8(16) - SAD_SSE_SUM_8(24) - SAD_SSE_SUM_8(32) - SAD_SSE_SUM_8(40) - SAD_SSE_SUM_8(48) - SAD_SSE_SUM_8(56) - - :: "r" (block1), "r" (block2) - ); - - h--; - block1 += ystride; - block2 += ystride; - } - SAD_SSE_FINISH(result) - return result; - -} -static __attribute__((used)) __attribute__((aligned(8))) uint64_t sad_sse_422_mask_chroma = 0x00ff00ff00ff00ffULL; - -#define SAD_SSE_422_LUMA_INIT \ - asm volatile ( "movq %0,%%mm7\n\t"\ - "pxor %%mm6,%%mm6\n\t" :: "m" (sad_sse_422_mask_chroma) );\ - -// Sum two 4x1 pixel blocks -#define SAD_SSE_422_LUMA_SUM_4(OFFSET) \ - "movq " #OFFSET "(%0),%%mm0 \n\t"\ - "movq " #OFFSET "(%1),%%mm1 \n\t"\ - "pand %%mm7,%%mm0 \n\t"\ - "pand %%mm7,%%mm1 \n\t"\ - "psadbw %%mm1,%%mm0 \n\t"\ - "paddw %%mm0,%%mm6 \n\t"\ - -static int sad_sse_422_luma_4x4( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - SAD_SSE_422_LUMA_INIT - #define ROW SAD_SSE_422_LUMA_SUM_4(0) SAD_SSE_NEXTROW - asm volatile ( ROW ROW ROW ROW - :: "r" (block1), "r" (block2), "r" ((intptr_t)(ystride))); - - SAD_SSE_FINISH(result) - return result; - #undef ROW - -} - -static int sad_sse_422_luma_8x8( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - SAD_SSE_422_LUMA_INIT - #define ROW SAD_SSE_422_LUMA_SUM_4(0) SAD_SSE_422_LUMA_SUM_4(8) SAD_SSE_NEXTROW - asm volatile ( ROW ROW ROW ROW ROW ROW ROW ROW - :: "r" (block1), "r" (block2), "r" ((intptr_t)(ystride))); - - SAD_SSE_FINISH(result) - return result; - #undef ROW - -} - -static int sad_sse_422_luma_16x16( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - SAD_SSE_422_LUMA_INIT - #define ROW SAD_SSE_422_LUMA_SUM_4(0) SAD_SSE_422_LUMA_SUM_4(8) SAD_SSE_422_LUMA_SUM_4(16) SAD_SSE_422_LUMA_SUM_4(24) SAD_SSE_NEXTROW - asm volatile ( ROW ROW ROW ROW ROW ROW ROW ROW - ROW ROW ROW ROW ROW ROW ROW ROW - :: "r" (block1), "r" (block2), "r" ((intptr_t)(ystride))); - - SAD_SSE_FINISH(result) - return result; - #undef ROW - -} - -static int sad_sse_422_luma_32x32( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - SAD_SSE_422_LUMA_INIT - #define ROW SAD_SSE_422_LUMA_SUM_4(0) SAD_SSE_422_LUMA_SUM_4(8) SAD_SSE_422_LUMA_SUM_4(16) SAD_SSE_422_LUMA_SUM_4(24)\ - SAD_SSE_422_LUMA_SUM_4(32) SAD_SSE_422_LUMA_SUM_4(40) SAD_SSE_422_LUMA_SUM_4(48) SAD_SSE_422_LUMA_SUM_4(56)\ - SAD_SSE_NEXTROW - - asm volatile ( ROW ROW ROW ROW ROW ROW ROW ROW - ROW ROW ROW ROW ROW ROW ROW ROW - ROW ROW ROW ROW ROW ROW ROW ROW - ROW ROW ROW ROW ROW ROW ROW ROW - :: "r" (block1), "r" (block2), "r" ((intptr_t)(ystride))); - - SAD_SSE_FINISH(result) - return result; - #undef ROW - -} - -static int sad_sse_422_luma_4w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - - SAD_SSE_422_LUMA_INIT - - while( h != 0 ) { - asm volatile ( - SAD_SSE_422_LUMA_SUM_4(0) - :: "r" (block1), "r" (block2) - ); - - h--; - block1 += ystride; - block2 += ystride; - } - SAD_SSE_FINISH(result) - return result; - -} - -static int sad_sse_422_luma_8w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - - SAD_SSE_422_LUMA_INIT - - while( h != 0 ) { - asm volatile ( - SAD_SSE_422_LUMA_SUM_4(0) - SAD_SSE_422_LUMA_SUM_4(8) - - :: "r" (block1), "r" (block2) - ); - - h--; - block1 += ystride; - block2 += ystride; - } - SAD_SSE_FINISH(result) - return result; - -} - -static int sad_sse_422_luma_16w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - - SAD_SSE_422_LUMA_INIT - - while( h != 0 ) { - asm volatile ( - SAD_SSE_422_LUMA_SUM_4(0) - SAD_SSE_422_LUMA_SUM_4(8) - SAD_SSE_422_LUMA_SUM_4(16) - SAD_SSE_422_LUMA_SUM_4(24) - - :: "r" (block1), "r" (block2) - ); - - h--; - block1 += ystride; - block2 += ystride; - } - SAD_SSE_FINISH(result) - return result; - -} - -static int sad_sse_422_luma_32w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - - SAD_SSE_422_LUMA_INIT - - while( h != 0 ) { - asm volatile ( - SAD_SSE_422_LUMA_SUM_4(0) - SAD_SSE_422_LUMA_SUM_4(8) - SAD_SSE_422_LUMA_SUM_4(16) - SAD_SSE_422_LUMA_SUM_4(24) - SAD_SSE_422_LUMA_SUM_4(32) - SAD_SSE_422_LUMA_SUM_4(40) - SAD_SSE_422_LUMA_SUM_4(48) - SAD_SSE_422_LUMA_SUM_4(56) - - :: "r" (block1), "r" (block2) - ); - - h--; - block1 += ystride; - block2 += ystride; - } - SAD_SSE_FINISH(result) - return result; - -} - -static int sad_sse_422_luma_64w( uint8_t *block1, uint8_t *block2, int xstride, int ystride, int w, int h ) -{ - int result; - - SAD_SSE_422_LUMA_INIT - - while( h != 0 ) { - asm volatile ( - SAD_SSE_422_LUMA_SUM_4(0) - SAD_SSE_422_LUMA_SUM_4(8) - SAD_SSE_422_LUMA_SUM_4(16) - SAD_SSE_422_LUMA_SUM_4(24) - SAD_SSE_422_LUMA_SUM_4(32) - SAD_SSE_422_LUMA_SUM_4(40) - SAD_SSE_422_LUMA_SUM_4(48) - SAD_SSE_422_LUMA_SUM_4(56) - SAD_SSE_422_LUMA_SUM_4(64) - SAD_SSE_422_LUMA_SUM_4(72) - SAD_SSE_422_LUMA_SUM_4(80) - SAD_SSE_422_LUMA_SUM_4(88) - SAD_SSE_422_LUMA_SUM_4(96) - SAD_SSE_422_LUMA_SUM_4(104) - SAD_SSE_422_LUMA_SUM_4(112) - SAD_SSE_422_LUMA_SUM_4(120) - - :: "r" (block1), "r" (block2) - ); - - h--; - block1 += ystride; - block2 += ystride; - } - SAD_SSE_FINISH(result) - return result; -} diff --git a/src/modules/opengl/CMakeLists.txt b/src/modules/movit/CMakeLists.txt similarity index 62% rename from src/modules/opengl/CMakeLists.txt rename to src/modules/movit/CMakeLists.txt index e81b3194b..cd4e84351 100644 --- a/src/modules/opengl/CMakeLists.txt +++ b/src/modules/movit/CMakeLists.txt @@ -1,5 +1,4 @@ -add_library(mltopengl MODULE - consumer_xgl.c +add_library(mltmovit MODULE factory.c filter_glsl_manager.cpp filter_movit_blur.cpp @@ -24,19 +23,24 @@ add_library(mltopengl MODULE transition_movit_overlay.cpp ) -target_link_libraries(mltopengl m Threads::Threads mlt mlt++ OpenGL::GL PkgConfig::movit) +target_compile_options(mltmovit PRIVATE ${MLT_COMPILE_OPTIONS}) +if(APPLE AND RELOCATABLE) + target_compile_definitions(mltmovit PRIVATE RELOCATABLE) +endif() + +target_link_libraries(mltmovit PRIVATE m Threads::Threads mlt mlt++ OpenGL::GL PkgConfig::movit) if(UNIX AND NOT APPLE) - target_link_libraries(mltopengl X11::X11) + target_sources(mltmovit PRIVATE consumer_xgl.c) + target_link_libraries(mltmovit PRIVATE X11::X11) endif() pkg_get_variable(SHADERDIR movit shaderdir) -target_compile_definitions(mltopengl PRIVATE SHADERDIR="${SHADERDIR}") +target_compile_definitions(mltmovit PRIVATE SHADERDIR="${SHADERDIR}") -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltopengl PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +set_target_properties(mltmovit PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(TARGETS mltopengl LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +install(TARGETS mltmovit LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES filter_movit_blur.yml @@ -54,5 +58,5 @@ install(FILES transition_movit_luma.yml transition_movit_mix.yml transition_movit_overlay.yml - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/opengl + DESTINATION ${MLT_INSTALL_DATA_DIR}/movit ) diff --git a/src/modules/opengl/Makefile b/src/modules/movit/Makefile similarity index 93% rename from src/modules/opengl/Makefile rename to src/modules/movit/Makefile index b78457ca6..48a2ef281 100644 --- a/src/modules/opengl/Makefile +++ b/src/modules/movit/Makefile @@ -4,7 +4,7 @@ CFLAGS := -I../.. $(CFLAGS) LDFLAGS := -L../../framework -lmlt -lm $(LDFLAGS) -TARGET = ../libmltopengl$(LIBSUF) +TARGET = ../libmltmovit$(LIBSUF) OBJS = factory.o @@ -75,8 +75,8 @@ clean: install: all install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" - install -d "$(DESTDIR)$(mltdatadir)/opengl" - install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/opengl" + install -d "$(DESTDIR)$(mltdatadir)/movit" + install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/movit" ifneq ($(wildcard .depend),) include .depend diff --git a/src/modules/opengl/configure b/src/modules/movit/configure similarity index 89% rename from src/modules/opengl/configure rename to src/modules/movit/configure index 3065ba126..7a4052bcb 100755 --- a/src/modules/opengl/configure +++ b/src/modules/movit/configure @@ -5,7 +5,7 @@ then if ! $(pkg-config movit) then echo "- movit not found: disabling" - touch ../disable-opengl + touch ../disable-movit exit 0 fi diff --git a/src/modules/opengl/consumer_xgl.c b/src/modules/movit/consumer_xgl.c similarity index 99% rename from src/modules/opengl/consumer_xgl.c rename to src/modules/movit/consumer_xgl.c index 76f7a16e3..1bc539a35 100644 --- a/src/modules/opengl/consumer_xgl.c +++ b/src/modules/movit/consumer_xgl.c @@ -220,7 +220,7 @@ static void show_frame() glEnd(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - mlt_events_fire( MLT_CONSUMER_PROPERTIES(&xgl->parent), "consumer-frame-show", new_frame.mlt_frame_ref, NULL ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES(&xgl->parent), "consumer-frame-show", mlt_event_data_from_frame(new_frame.mlt_frame_ref) ); mlt_frame_close( new_frame.mlt_frame_ref ); new_frame.mlt_frame_ref = NULL; @@ -264,7 +264,7 @@ void* video_thread( void *arg ) if ( mlt_properties_get_int( properties, "rendered" ) == 1 ) { // Get the image, width and height - mlt_image_format vfmt = mlt_image_glsl_texture; + mlt_image_format vfmt = mlt_image_opengl_texture; int width = 0, height = 0; GLuint *image = 0; int error = mlt_frame_get_image( next, (uint8_t**) &image, &vfmt, &width, &height, 0 ); @@ -524,7 +524,7 @@ static void on_consumer_thread_started( mlt_properties owner, HiddenContext* con { // Initialize this thread's OpenGL state glXMakeCurrent( context->dpy, context->win, context->ctx ); - mlt_events_fire( MLT_FILTER_PROPERTIES(glsl_manager), "init glsl", NULL ); + mlt_events_fire( MLT_FILTER_PROPERTIES(glsl_manager), "init glsl", mlt_event_data_none() ); } /** Forward references to static functions. diff --git a/src/modules/opengl/factory.c b/src/modules/movit/factory.c similarity index 50% rename from src/modules/opengl/factory.c rename to src/modules/movit/factory.c index d92ddb894..ce19b0d3f 100644 --- a/src/modules/opengl/factory.c +++ b/src/modules/movit/factory.c @@ -48,49 +48,49 @@ extern mlt_transition transition_movit_overlay_init( mlt_profile profile, mlt_se static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; - snprintf( file, PATH_MAX, "%s/opengl/%s", mlt_environment( "MLT_DATA" ), (char*) data ); + snprintf( file, PATH_MAX, "%s/movit/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { #if !defined(__APPLE__) && !defined(_WIN32) - MLT_REGISTER( consumer_type, "xgl", consumer_xgl_init ); + MLT_REGISTER( mlt_service_consumer_type, "xgl", consumer_xgl_init ); #endif - MLT_REGISTER( filter_type, "glsl.manager", filter_glsl_manager_init ); - MLT_REGISTER( filter_type, "movit.blur", filter_movit_blur_init ); - MLT_REGISTER( filter_type, "movit.convert", filter_movit_convert_init ); - MLT_REGISTER( filter_type, "movit.crop", filter_movit_crop_init ); - MLT_REGISTER( filter_type, "movit.diffusion", filter_movit_diffusion_init ); - MLT_REGISTER( filter_type, "movit.flip", filter_movit_flip_init ); - MLT_REGISTER( filter_type, "movit.glow", filter_movit_glow_init ); - MLT_REGISTER( filter_type, "movit.lift_gamma_gain", filter_lift_gamma_gain_init ); - MLT_REGISTER( filter_type, "movit.mirror", filter_movit_mirror_init ); - MLT_REGISTER( filter_type, "movit.opacity", filter_movit_opacity_init ); - MLT_REGISTER( filter_type, "movit.rect", filter_movit_rect_init ); - MLT_REGISTER( filter_type, "movit.resample", filter_movit_resample_init ); - MLT_REGISTER( filter_type, "movit.resize", filter_movit_resize_init ); - MLT_REGISTER( filter_type, "movit.saturation", filter_movit_saturation_init ); - MLT_REGISTER( filter_type, "movit.sharpen", filter_deconvolution_sharpen_init ); - MLT_REGISTER( filter_type, "movit.vignette", filter_movit_vignette_init ); - MLT_REGISTER( filter_type, "movit.white_balance", filter_white_balance_init ); - MLT_REGISTER( transition_type, "movit.luma_mix", transition_movit_luma_init ); - MLT_REGISTER( transition_type, "movit.mix", transition_movit_mix_init ); - MLT_REGISTER( transition_type, "movit.overlay", transition_movit_overlay_init ); + MLT_REGISTER( mlt_service_filter_type, "glsl.manager", filter_glsl_manager_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.blur", filter_movit_blur_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.convert", filter_movit_convert_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.crop", filter_movit_crop_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.diffusion", filter_movit_diffusion_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.flip", filter_movit_flip_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.glow", filter_movit_glow_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.lift_gamma_gain", filter_lift_gamma_gain_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.mirror", filter_movit_mirror_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.opacity", filter_movit_opacity_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.rect", filter_movit_rect_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.resample", filter_movit_resample_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.resize", filter_movit_resize_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.saturation", filter_movit_saturation_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.sharpen", filter_deconvolution_sharpen_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.vignette", filter_movit_vignette_init ); + MLT_REGISTER( mlt_service_filter_type, "movit.white_balance", filter_white_balance_init ); + MLT_REGISTER( mlt_service_transition_type, "movit.luma_mix", transition_movit_luma_init ); + 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( filter_type, "movit.blur", metadata, "filter_movit_blur.yml" ); - MLT_REGISTER_METADATA( filter_type, "movit.diffusion", metadata, "filter_movit_diffusion.yml" ); - MLT_REGISTER_METADATA( filter_type, "movit.flip", metadata, "filter_movit_flip.yml" ); - MLT_REGISTER_METADATA( filter_type, "movit.glow", metadata, "filter_movit_glow.yml" ); - MLT_REGISTER_METADATA( filter_type, "movit.lift_gamma_gain", metadata, "filter_movit_lift_gamma_gain.yml" ); - MLT_REGISTER_METADATA( filter_type, "movit.mirror", metadata, "filter_movit_mirror.yml" ); - MLT_REGISTER_METADATA( filter_type, "movit.opacity", metadata, "filter_movit_opacity.yml" ); - MLT_REGISTER_METADATA( filter_type, "movit.rect", metadata, "filter_movit_rect.yml" ); - MLT_REGISTER_METADATA( filter_type, "movit.saturation", metadata, "filter_movit_saturation.yml" ); - MLT_REGISTER_METADATA( filter_type, "movit.sharpen", metadata, "filter_movit_deconvolution_sharpen.yml" ); - MLT_REGISTER_METADATA( filter_type, "movit.vignette", metadata, "filter_movit_vignette.yml" ); - MLT_REGISTER_METADATA( filter_type, "movit.white_balance", metadata, "filter_movit_white_balance.yml" ); - MLT_REGISTER_METADATA( transition_type, "movit.luma_mix", metadata, "transition_movit_luma.yml" ); - MLT_REGISTER_METADATA( transition_type, "movit.mix", metadata, "transition_movit_mix.yml" ); - MLT_REGISTER_METADATA( transition_type, "movit.overlay", metadata, "transition_movit_overlay.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.blur", metadata, "filter_movit_blur.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" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.lift_gamma_gain", metadata, "filter_movit_lift_gamma_gain.yml" ); + 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.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" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "movit.white_balance", metadata, "filter_movit_white_balance.yml" ); + MLT_REGISTER_METADATA( mlt_service_transition_type, "movit.luma_mix", metadata, "transition_movit_luma.yml" ); + MLT_REGISTER_METADATA( mlt_service_transition_type, "movit.mix", metadata, "transition_movit_mix.yml" ); + MLT_REGISTER_METADATA( mlt_service_transition_type, "movit.overlay", metadata, "transition_movit_overlay.yml" ); } diff --git a/src/modules/opengl/filter_glsl_manager.cpp b/src/modules/movit/filter_glsl_manager.cpp similarity index 99% rename from src/modules/opengl/filter_glsl_manager.cpp rename to src/modules/movit/filter_glsl_manager.cpp index f2f4ec61e..0ce8bfd2d 100644 --- a/src/modules/opengl/filter_glsl_manager.cpp +++ b/src/modules/movit/filter_glsl_manager.cpp @@ -70,8 +70,8 @@ GlslManager::GlslManager() filter->child = this; add_ref(mlt_global_properties()); - mlt_events_register( get_properties(), "init glsl", NULL ); - mlt_events_register( get_properties(), "close glsl", NULL ); + mlt_events_register( get_properties(), "init glsl" ); + mlt_events_register( get_properties(), "close glsl" ); initEvent = listen("init glsl", this, (mlt_listener) GlslManager::onInit); closeEvent = listen("close glsl", this, (mlt_listener) GlslManager::onClose); } @@ -235,7 +235,7 @@ void GlslManager::cleanupContext() unlock(); } -void GlslManager::onInit( mlt_properties owner, GlslManager* filter ) +void GlslManager::onInit( mlt_properties owner, GlslManager* filter, mlt_event_data ) { mlt_log_debug( filter->get_service(), "%s\n", __FUNCTION__ ); #ifdef _WIN32 @@ -249,7 +249,7 @@ void GlslManager::onInit( mlt_properties owner, GlslManager* filter ) filter->set( "glsl_supported", success ); } -void GlslManager::onClose( mlt_properties owner, GlslManager *filter ) +void GlslManager::onClose( mlt_properties owner, GlslManager *filter, mlt_event_data ) { filter->cleanupContext(); } diff --git a/src/modules/opengl/filter_glsl_manager.h b/src/modules/movit/filter_glsl_manager.h similarity index 96% rename from src/modules/opengl/filter_glsl_manager.h rename to src/modules/movit/filter_glsl_manager.h index 0c365ef8b..f416cfbcb 100644 --- a/src/modules/opengl/filter_glsl_manager.h +++ b/src/modules/movit/filter_glsl_manager.h @@ -129,8 +129,8 @@ class GlslManager : public Mlt::Filter static void* get_frame_specific_data( mlt_service service, mlt_frame frame, const char *key, int *length ); static int set_frame_specific_data( mlt_service service, mlt_frame frame, const char *key, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise ); - static void onInit( mlt_properties owner, GlslManager* filter ); - static void onClose( mlt_properties owner, GlslManager* filter ); + static void onInit(mlt_properties owner, GlslManager* filter, mlt_event_data ); + static void onClose( mlt_properties owner, GlslManager* filter, mlt_event_data ); static void onServiceChanged( mlt_properties owner, mlt_service service ); static void onPropertyChanged( mlt_properties owner, mlt_service service, const char* property ); movit::ResourcePool* resource_pool; diff --git a/src/modules/opengl/filter_movit_blur.cpp b/src/modules/movit/filter_movit_blur.cpp similarity index 98% rename from src/modules/opengl/filter_movit_blur.cpp rename to src/modules/movit/filter_movit_blur.cpp index c7339bc0a..23dc958cf 100644 --- a/src/modules/opengl/filter_movit_blur.cpp +++ b/src/modules/movit/filter_movit_blur.cpp @@ -36,7 +36,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_filter_get_length2( filter, frame ) ); mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter)); GlslManager::get_instance()->unlock_service( frame ); - *format = mlt_image_glsl; + *format = mlt_image_movit; int error = mlt_frame_get_image( frame, image, format, width, height, writable ); if (*width < 1 || *height < 1) { diff --git a/src/modules/opengl/filter_movit_blur.yml b/src/modules/movit/filter_movit_blur.yml similarity index 100% rename from src/modules/opengl/filter_movit_blur.yml rename to src/modules/movit/filter_movit_blur.yml diff --git a/src/modules/opengl/filter_movit_convert.cpp b/src/modules/movit/filter_movit_convert.cpp similarity index 97% rename from src/modules/opengl/filter_movit_convert.cpp rename to src/modules/movit/filter_movit_convert.cpp index 3d06d6184..cc974efd2 100644 --- a/src/modules/opengl/filter_movit_convert.cpp +++ b/src/modules/movit/filter_movit_convert.cpp @@ -454,13 +454,13 @@ static int movit_render( EffectChain *chain, mlt_frame frame, mlt_image_format * GlslManager* glsl = GlslManager::get_instance(); int error; - if ( output_format == mlt_image_glsl_texture ) { + if ( output_format == mlt_image_opengl_texture ) { error = glsl->render_frame_texture( chain, frame, width, height, image ); } else { error = glsl->render_frame_rgba( chain, frame, width, height, image ); - if ( !error && output_format != mlt_image_rgb24a ) { - *format = mlt_image_rgb24a; + if ( !error && output_format != mlt_image_rgba ) { + *format = mlt_image_rgba; error = convert_on_cpu( frame, image, format, output_format ); } } @@ -476,11 +476,11 @@ static MltInput* create_input( mlt_properties properties, mlt_image_format forma } MltInput* input = new MltInput( format ); - if ( format == mlt_image_rgb24a || format == mlt_image_opengl ) { + if ( format == mlt_image_rgba ) { // TODO: Get the color space if available. input->useFlatInput( FORMAT_RGBA_POSTMULTIPLIED_ALPHA, width, height ); } - else if ( format == mlt_image_rgb24 ) { + else if ( format == mlt_image_rgb ) { // TODO: Get the color space if available. input->useFlatInput( FORMAT_RGB, width, height ); } @@ -512,9 +512,7 @@ static uint8_t* make_input_copy( mlt_image_format format, uint8_t *image, int wi return NULL; } - // We use height-1 because mlt_image_format_size() uses height + 1. - // XXX Remove -1 when mlt_image_format_size() is changed. - int img_size = mlt_image_format_size( format, width, height - 1, NULL ); + int img_size = mlt_image_format_size( format, width, height, NULL ); uint8_t* img_copy = (uint8_t*) mlt_pool_alloc( img_size ); if ( format == mlt_image_yuv422 ) { yuv422_to_yuv422p( image, img_copy, width, height ); @@ -542,7 +540,7 @@ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *fo return convert_on_cpu( frame, image, format, output_format ); // Do non-GL image conversions on a CPU-based image converter. - if ( *format != mlt_image_glsl && output_format != mlt_image_glsl && output_format != mlt_image_glsl_texture ) + if ( *format != mlt_image_movit && output_format != mlt_image_movit && output_format != mlt_image_opengl_texture ) return convert_on_cpu( frame, image, format, output_format ); int error = 0; @@ -558,7 +556,7 @@ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *fo // If we're at the beginning of a series of Movit effects, store the input // sent into the chain. - if ( output_format == mlt_image_glsl ) { + if ( output_format == mlt_image_movit ) { mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); MltInput *input = create_input( properties, *format, profile->width, profile->height, width, height ); @@ -582,7 +580,7 @@ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *fo } // If we're at the _end_ of a series of Movit effects, render the chain. - if ( *format == mlt_image_glsl ) { + if ( *format == mlt_image_movit ) { mlt_service leaf_service = (mlt_service) *image; if ( leaf_service == (mlt_service) -1 ) { @@ -613,8 +611,8 @@ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *fo // If we've been asked to render some frame directly to a texture (without any // effects in-between), we create a new mini-chain to do so. - if ( *format != mlt_image_glsl && output_format == mlt_image_glsl_texture ) { - // We might already have a texture from a previous conversion from mlt_image_glsl. + if ( *format != mlt_image_movit && output_format == mlt_image_opengl_texture ) { + // We might already have a texture from a previous conversion from mlt_image_movit. glsl_texture texture = (glsl_texture) mlt_properties_get_data( properties, "movit.convert.texture", NULL ); // XXX: requires a special property set on the frame by the app for now // because we do not have reliable way to clear the texture property diff --git a/src/modules/opengl/filter_movit_crop.cpp b/src/modules/movit/filter_movit_crop.cpp similarity index 97% rename from src/modules/opengl/filter_movit_crop.cpp rename to src/modules/movit/filter_movit_crop.cpp index 6e2d83906..04f4c8a26 100644 --- a/src/modules/opengl/filter_movit_crop.cpp +++ b/src/modules/movit/filter_movit_crop.cpp @@ -60,7 +60,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format // Get the image as requested // *format = (mlt_image_format) mlt_properties_get_int( MLT_PRODUCER_PROPERTIES(producer), "_movit image_format" ); - // This is needed to prevent conversion to mlt_image_glsl after producer, + // This is needed to prevent conversion to mlt_image_movit after producer, // deinterlace, or fieldorder, The latter two can force output of // an image after it had already been converted to glsl. *format = mlt_image_none; @@ -71,10 +71,10 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format if ( requested_format == mlt_image_none ) return error; - if ( !error && *format != mlt_image_glsl && frame->convert_image ) { + if ( !error && *format != mlt_image_movit && frame->convert_image ) { // Pin the requested format to the first one returned. // mlt_properties_set_int( MLT_PRODUCER_PROPERTIES(producer), "_movit image_format", *format ); - error = frame->convert_image( frame, image, format, mlt_image_glsl ); + error = frame->convert_image( frame, image, format, mlt_image_movit ); } if ( !error ) { double left = mlt_properties_get_double( properties, "crop.left" ); diff --git a/src/modules/opengl/filter_movit_deconvolution_sharpen.cpp b/src/modules/movit/filter_movit_deconvolution_sharpen.cpp similarity index 99% rename from src/modules/opengl/filter_movit_deconvolution_sharpen.cpp rename to src/modules/movit/filter_movit_deconvolution_sharpen.cpp index 045ac0977..b836dd095 100644 --- a/src/modules/opengl/filter_movit_deconvolution_sharpen.cpp +++ b/src/modules/movit/filter_movit_deconvolution_sharpen.cpp @@ -55,7 +55,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_properties_set( properties, "_movit fingerprint", fingerprint ); GlslManager::get_instance()->unlock_service( frame ); - *format = mlt_image_glsl; + *format = mlt_image_movit; int error = mlt_frame_get_image( frame, image, format, width, height, writable ); if (*width < 1 || *height < 1) { diff --git a/src/modules/opengl/filter_movit_deconvolution_sharpen.yml b/src/modules/movit/filter_movit_deconvolution_sharpen.yml similarity index 100% rename from src/modules/opengl/filter_movit_deconvolution_sharpen.yml rename to src/modules/movit/filter_movit_deconvolution_sharpen.yml diff --git a/src/modules/opengl/filter_movit_diffusion.cpp b/src/modules/movit/filter_movit_diffusion.cpp similarity index 99% rename from src/modules/opengl/filter_movit_diffusion.cpp rename to src/modules/movit/filter_movit_diffusion.cpp index 8f061a3bd..0b54c2887 100644 --- a/src/modules/opengl/filter_movit_diffusion.cpp +++ b/src/modules/movit/filter_movit_diffusion.cpp @@ -39,7 +39,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_properties_set_double( properties, "_movit.parms.float.blurred_mix_amount", mlt_properties_anim_get_double( properties, "mix", position, length ) ); GlslManager::get_instance()->unlock_service( frame ); - *format = mlt_image_glsl; + *format = mlt_image_movit; int error = mlt_frame_get_image( frame, image, format, width, height, writable ); if (*width < 1 || *height < 1) { diff --git a/src/modules/opengl/filter_movit_diffusion.yml b/src/modules/movit/filter_movit_diffusion.yml similarity index 100% rename from src/modules/opengl/filter_movit_diffusion.yml rename to src/modules/movit/filter_movit_diffusion.yml diff --git a/src/modules/opengl/filter_movit_flip.cpp b/src/modules/movit/filter_movit_flip.cpp similarity index 98% rename from src/modules/opengl/filter_movit_flip.cpp rename to src/modules/movit/filter_movit_flip.cpp index f62645030..77001b500 100644 --- a/src/modules/opengl/filter_movit_flip.cpp +++ b/src/modules/movit/filter_movit_flip.cpp @@ -31,7 +31,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); - *format = mlt_image_glsl; + *format = mlt_image_movit; int error = mlt_frame_get_image( frame, image, format, width, height, writable ); if (*width < 1 || *height < 1) { diff --git a/src/modules/opengl/filter_movit_flip.yml b/src/modules/movit/filter_movit_flip.yml similarity index 100% rename from src/modules/opengl/filter_movit_flip.yml rename to src/modules/movit/filter_movit_flip.yml diff --git a/src/modules/opengl/filter_movit_glow.cpp b/src/modules/movit/filter_movit_glow.cpp similarity index 99% rename from src/modules/opengl/filter_movit_glow.cpp rename to src/modules/movit/filter_movit_glow.cpp index 060b9e98b..2922dc694 100644 --- a/src/modules/opengl/filter_movit_glow.cpp +++ b/src/modules/movit/filter_movit_glow.cpp @@ -42,7 +42,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_properties_set_double( properties, "_movit.parms.float.highlight_cutoff", mlt_properties_anim_get_double( properties, "highlight_cutoff", position, length ) ); GlslManager::get_instance()->unlock_service( frame ); - *format = mlt_image_glsl; + *format = mlt_image_movit; int error = mlt_frame_get_image( frame, image, format, width, height, writable ); if (*width < 1 || *height < 1) { diff --git a/src/modules/opengl/filter_movit_glow.yml b/src/modules/movit/filter_movit_glow.yml similarity index 100% rename from src/modules/opengl/filter_movit_glow.yml rename to src/modules/movit/filter_movit_glow.yml diff --git a/src/modules/opengl/filter_movit_lift_gamma_gain.cpp b/src/modules/movit/filter_movit_lift_gamma_gain.cpp similarity index 99% rename from src/modules/opengl/filter_movit_lift_gamma_gain.cpp rename to src/modules/movit/filter_movit_lift_gamma_gain.cpp index b98c59c98..20e60baad 100644 --- a/src/modules/opengl/filter_movit_lift_gamma_gain.cpp +++ b/src/modules/movit/filter_movit_lift_gamma_gain.cpp @@ -53,7 +53,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_properties_set_double( properties, "_movit.parms.vec3.gain[2]", mlt_properties_anim_get_double( properties, "gain_b", position, length ) ); GlslManager::get_instance()->unlock_service( frame ); - *format = mlt_image_glsl; + *format = mlt_image_movit; int error = mlt_frame_get_image( frame, image, format, width, height, writable ); if (*width < 1 || *height < 1) { diff --git a/src/modules/opengl/filter_movit_lift_gamma_gain.yml b/src/modules/movit/filter_movit_lift_gamma_gain.yml similarity index 100% rename from src/modules/opengl/filter_movit_lift_gamma_gain.yml rename to src/modules/movit/filter_movit_lift_gamma_gain.yml diff --git a/src/modules/opengl/filter_movit_mirror.cpp b/src/modules/movit/filter_movit_mirror.cpp similarity index 98% rename from src/modules/opengl/filter_movit_mirror.cpp rename to src/modules/movit/filter_movit_mirror.cpp index b0103e53a..c6a03be7d 100644 --- a/src/modules/opengl/filter_movit_mirror.cpp +++ b/src/modules/movit/filter_movit_mirror.cpp @@ -30,7 +30,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); - *format = mlt_image_glsl; + *format = mlt_image_movit; int error = mlt_frame_get_image( frame, image, format, width, height, writable ); if (*width < 1 || *height < 1) { diff --git a/src/modules/opengl/filter_movit_mirror.yml b/src/modules/movit/filter_movit_mirror.yml similarity index 100% rename from src/modules/opengl/filter_movit_mirror.yml rename to src/modules/movit/filter_movit_mirror.yml diff --git a/src/modules/opengl/filter_movit_opacity.cpp b/src/modules/movit/filter_movit_opacity.cpp similarity index 99% rename from src/modules/opengl/filter_movit_opacity.cpp rename to src/modules/movit/filter_movit_opacity.cpp index 09f371b92..655029b00 100644 --- a/src/modules/opengl/filter_movit_opacity.cpp +++ b/src/modules/movit/filter_movit_opacity.cpp @@ -41,7 +41,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_properties_set_double( properties, "_movit.parms.vec4.factor[2]", opacity ); mlt_properties_set_double( properties, "_movit.parms.vec4.factor[3]", alpha >= 0 ? alpha : opacity ); GlslManager::get_instance()->unlock_service( frame ); - *format = mlt_image_glsl; + *format = mlt_image_movit; int error = mlt_frame_get_image( frame, image, format, width, height, writable ); if (*width < 1 || *height < 1) { diff --git a/src/modules/opengl/filter_movit_opacity.yml b/src/modules/movit/filter_movit_opacity.yml similarity index 100% rename from src/modules/opengl/filter_movit_opacity.yml rename to src/modules/movit/filter_movit_opacity.yml diff --git a/src/modules/opengl/filter_movit_rect.cpp b/src/modules/movit/filter_movit_rect.cpp similarity index 100% rename from src/modules/opengl/filter_movit_rect.cpp rename to src/modules/movit/filter_movit_rect.cpp diff --git a/src/modules/opengl/filter_movit_rect.yml b/src/modules/movit/filter_movit_rect.yml similarity index 100% rename from src/modules/opengl/filter_movit_rect.yml rename to src/modules/movit/filter_movit_rect.yml diff --git a/src/modules/opengl/filter_movit_resample.cpp b/src/modules/movit/filter_movit_resample.cpp similarity index 99% rename from src/modules/opengl/filter_movit_resample.cpp rename to src/modules/movit/filter_movit_resample.cpp index d73cda1b3..749253bcc 100644 --- a/src/modules/opengl/filter_movit_resample.cpp +++ b/src/modules/movit/filter_movit_resample.cpp @@ -76,7 +76,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format // Get the image as requested if ( *format != mlt_image_none ) - *format = mlt_image_glsl; + *format = mlt_image_movit; int error = mlt_frame_get_image( frame, image, format, &iwidth, &iheight, writable ); if (*width < 1 || *height < 1 || iwidth < 1 || iheight < 1 || owidth < 1 || oheight < 1) { diff --git a/src/modules/opengl/filter_movit_resize.cpp b/src/modules/movit/filter_movit_resize.cpp similarity index 99% rename from src/modules/opengl/filter_movit_resize.cpp rename to src/modules/movit/filter_movit_resize.cpp index 883c0dac9..4742b30ba 100644 --- a/src/modules/opengl/filter_movit_resize.cpp +++ b/src/modules/movit/filter_movit_resize.cpp @@ -150,7 +150,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_properties_set_int( properties, "distort", 0 ); // Now get the image - *format = mlt_image_glsl; + *format = mlt_image_movit; error = mlt_frame_get_image( frame, image, format, &owidth, &oheight, writable ); // Offset the position according to alignment diff --git a/src/modules/opengl/filter_movit_saturation.cpp b/src/modules/movit/filter_movit_saturation.cpp similarity index 98% rename from src/modules/opengl/filter_movit_saturation.cpp rename to src/modules/movit/filter_movit_saturation.cpp index 5d80381f8..153150171 100644 --- a/src/modules/opengl/filter_movit_saturation.cpp +++ b/src/modules/movit/filter_movit_saturation.cpp @@ -37,7 +37,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_properties_set_double( properties, "_movit.parms.float.saturation", mlt_properties_anim_get_double( properties, "saturation", position, length ) ); GlslManager::get_instance()->unlock_service( frame ); - *format = mlt_image_glsl; + *format = mlt_image_movit; int error = mlt_frame_get_image( frame, image, format, width, height, writable ); if (*width < 1 || *height < 1) { diff --git a/src/modules/opengl/filter_movit_saturation.yml b/src/modules/movit/filter_movit_saturation.yml similarity index 100% rename from src/modules/opengl/filter_movit_saturation.yml rename to src/modules/movit/filter_movit_saturation.yml diff --git a/src/modules/opengl/filter_movit_vignette.cpp b/src/modules/movit/filter_movit_vignette.cpp similarity index 99% rename from src/modules/opengl/filter_movit_vignette.cpp rename to src/modules/movit/filter_movit_vignette.cpp index 6b6797c26..da881ed80 100644 --- a/src/modules/opengl/filter_movit_vignette.cpp +++ b/src/modules/movit/filter_movit_vignette.cpp @@ -39,7 +39,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_properties_set_double( properties, "_movit.parms.float.inner_radius", mlt_properties_anim_get_double( properties, "inner_radius", position, length ) ); GlslManager::get_instance()->unlock_service( frame ); - *format = mlt_image_glsl; + *format = mlt_image_movit; int error = mlt_frame_get_image( frame, image, format, width, height, writable ); if (*width < 1 || *height < 1) { diff --git a/src/modules/opengl/filter_movit_vignette.yml b/src/modules/movit/filter_movit_vignette.yml similarity index 100% rename from src/modules/opengl/filter_movit_vignette.yml rename to src/modules/movit/filter_movit_vignette.yml diff --git a/src/modules/opengl/filter_movit_white_balance.cpp b/src/modules/movit/filter_movit_white_balance.cpp similarity index 99% rename from src/modules/opengl/filter_movit_white_balance.cpp rename to src/modules/movit/filter_movit_white_balance.cpp index 9cc009732..83ce4facc 100644 --- a/src/modules/opengl/filter_movit_white_balance.cpp +++ b/src/modules/movit/filter_movit_white_balance.cpp @@ -59,7 +59,7 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_properties_set_double( properties, "_movit.parms.float.output_color_temperature", output_color_temperature ); GlslManager::get_instance()->unlock_service( frame ); - *format = mlt_image_glsl; + *format = mlt_image_movit; int error = mlt_frame_get_image( frame, image, format, width, height, writable ); if (*width < 1 || *height < 1) { diff --git a/src/modules/opengl/filter_movit_white_balance.yml b/src/modules/movit/filter_movit_white_balance.yml similarity index 100% rename from src/modules/opengl/filter_movit_white_balance.yml rename to src/modules/movit/filter_movit_white_balance.yml diff --git a/src/modules/opengl/mlt_flip_effect.h b/src/modules/movit/mlt_flip_effect.h similarity index 100% rename from src/modules/opengl/mlt_flip_effect.h rename to src/modules/movit/mlt_flip_effect.h diff --git a/src/modules/opengl/mlt_movit_input.cpp b/src/modules/movit/mlt_movit_input.cpp similarity index 100% rename from src/modules/opengl/mlt_movit_input.cpp rename to src/modules/movit/mlt_movit_input.cpp diff --git a/src/modules/opengl/mlt_movit_input.h b/src/modules/movit/mlt_movit_input.h similarity index 100% rename from src/modules/opengl/mlt_movit_input.h rename to src/modules/movit/mlt_movit_input.h diff --git a/src/modules/opengl/optional_effect.h b/src/modules/movit/optional_effect.h similarity index 100% rename from src/modules/opengl/optional_effect.h rename to src/modules/movit/optional_effect.h diff --git a/src/modules/opengl/transition_movit_luma.cpp b/src/modules/movit/transition_movit_luma.cpp similarity index 99% rename from src/modules/opengl/transition_movit_luma.cpp rename to src/modules/movit/transition_movit_luma.cpp index f398d433a..0cf495387 100644 --- a/src/modules/opengl/transition_movit_luma.cpp +++ b/src/modules/movit/transition_movit_luma.cpp @@ -69,7 +69,7 @@ static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *form uint8_t *a_image, *b_image, *c_image; // Get the images. - *format = mlt_image_glsl; + *format = mlt_image_movit; error = mlt_frame_get_image( a_frame, &a_image, format, width, height, writable ); error = mlt_frame_get_image( b_frame, &b_image, format, width, height, writable ); error = mlt_frame_get_image( c_frame, &c_image, format, width, height, writable ); @@ -96,7 +96,7 @@ static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *form uint8_t *a_image, *b_image; // Get the two images. - *format = mlt_image_glsl; + *format = mlt_image_movit; error = mlt_frame_get_image( a_frame, &a_image, format, width, height, writable ); error = mlt_frame_get_image( b_frame, &b_image, format, width, height, writable ); diff --git a/src/modules/opengl/transition_movit_luma.yml b/src/modules/movit/transition_movit_luma.yml similarity index 100% rename from src/modules/opengl/transition_movit_luma.yml rename to src/modules/movit/transition_movit_luma.yml diff --git a/src/modules/opengl/transition_movit_mix.cpp b/src/modules/movit/transition_movit_mix.cpp similarity index 99% rename from src/modules/opengl/transition_movit_mix.cpp rename to src/modules/movit/transition_movit_mix.cpp index 41b282fa7..bf4c6ad59 100644 --- a/src/modules/opengl/transition_movit_mix.cpp +++ b/src/modules/movit/transition_movit_mix.cpp @@ -64,7 +64,7 @@ static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *form uint8_t *a_image, *b_image; // Get the two images. - *format = mlt_image_glsl; + *format = mlt_image_movit; error = mlt_frame_get_image( a_frame, &a_image, format, width, height, writable ); error = mlt_frame_get_image( b_frame, &b_image, format, width, height, writable ); diff --git a/src/modules/opengl/transition_movit_mix.yml b/src/modules/movit/transition_movit_mix.yml similarity index 100% rename from src/modules/opengl/transition_movit_mix.yml rename to src/modules/movit/transition_movit_mix.yml diff --git a/src/modules/opengl/transition_movit_overlay.cpp b/src/modules/movit/transition_movit_overlay.cpp similarity index 99% rename from src/modules/opengl/transition_movit_overlay.cpp rename to src/modules/movit/transition_movit_overlay.cpp index 2c1e883f9..535fd9143 100644 --- a/src/modules/opengl/transition_movit_overlay.cpp +++ b/src/modules/movit/transition_movit_overlay.cpp @@ -45,7 +45,7 @@ static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *form uint8_t *a_image, *b_image; // Get the two images. - *format = mlt_image_glsl; + *format = mlt_image_movit; error = mlt_frame_get_image( a_frame, &a_image, format, width, height, writable ); error = mlt_frame_get_image( b_frame, &b_image, format, width, height, writable ); diff --git a/src/modules/opengl/transition_movit_overlay.yml b/src/modules/movit/transition_movit_overlay.yml similarity index 100% rename from src/modules/opengl/transition_movit_overlay.yml rename to src/modules/movit/transition_movit_overlay.yml diff --git a/src/modules/ndi/CMakeLists.txt b/src/modules/ndi/CMakeLists.txt new file mode 100644 index 000000000..94835fd74 --- /dev/null +++ b/src/modules/ndi/CMakeLists.txt @@ -0,0 +1,18 @@ +add_library(mltndi MODULE + consumer_ndi.c + factory.c + producer_ndi.c +) + +target_compile_options(mltndi PRIVATE ${MLT_COMPILE_OPTIONS}) + +target_link_libraries(mltndi PRIVATE mlt NDI::NDI) + +if(CPU_SSE) + target_compile_definitions(mltndi PRIVATE USE_SSE) +endif() + +set_target_properties(mltndi PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") + +install(TARGETS mltndi LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) +install(FILES consumer_ndi.yml producer_ndi.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/ndi) diff --git a/src/modules/ndi/consumer_ndi.c b/src/modules/ndi/consumer_ndi.c index 012ea3fc9..cd4064ab9 100644 --- a/src/modules/ndi/consumer_ndi.c +++ b/src/modules/ndi/consumer_ndi.c @@ -102,7 +102,7 @@ static void* consumer_ndi_feeder( void* p ) int m_isKeyer = 0, width = profile->width, height = profile->height; uint8_t* image = 0; mlt_frame frm = m_isKeyer ? frame : last; - mlt_image_format format = 0 ? mlt_image_rgb24a : mlt_image_yuv422; + mlt_image_format format = 0 ? mlt_image_rgba : mlt_image_yuv422; int rendered = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frm ), "rendered" ); if ( rendered && !mlt_frame_get_image( frm, &image, &format, &width, &height, 0 ) ) @@ -238,7 +238,7 @@ static void* consumer_ndi_feeder( void* p ) last = frame; } - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); } NDIlib_send_destroy( ndi_send ); diff --git a/src/modules/ndi/factory.c b/src/modules/ndi/factory.c index da63a50ba..e2b477970 100644 --- a/src/modules/ndi/factory.c +++ b/src/modules/ndi/factory.c @@ -110,9 +110,9 @@ static void *create_service( mlt_profile profile, mlt_service_type type, const c return NULL; } - if ( type == producer_type ) + if ( type == mlt_service_producer_type ) return producer_ndi_init( profile, type, id, (char*)arg ); - else if ( type == consumer_type ) + else if ( type == mlt_service_consumer_type ) return consumer_ndi_init( profile, type, id, (char*)arg ); return NULL; @@ -120,6 +120,6 @@ static void *create_service( mlt_profile profile, mlt_service_type type, const c MLT_REPOSITORY { - MLT_REGISTER( consumer_type, "ndi", create_service ); - MLT_REGISTER( producer_type, "ndi", create_service ); + MLT_REGISTER( mlt_service_consumer_type, "ndi", create_service ); + MLT_REGISTER( mlt_service_producer_type, "ndi", create_service ); } diff --git a/src/modules/ndi/producer_ndi.c b/src/modules/ndi/producer_ndi.c index d27b2532f..74bd517b4 100644 --- a/src/modules/ndi/producer_ndi.c +++ b/src/modules/ndi/producer_ndi.c @@ -295,7 +295,7 @@ static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *forma else if ( NDIlib_FourCC_type_RGBA == video->FourCC || NDIlib_FourCC_type_RGBX == video->FourCC ) { dst_stride = 4 * video->xres; - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; } else *format = mlt_image_none; diff --git a/src/modules/normalize/CMakeLists.txt b/src/modules/normalize/CMakeLists.txt index cce6b8926..55b0b8a74 100644 --- a/src/modules/normalize/CMakeLists.txt +++ b/src/modules/normalize/CMakeLists.txt @@ -4,15 +4,16 @@ add_library(mltnormalize MODULE filter_volume.c ) -target_link_libraries(mltnormalize mlt m) +target_compile_options(mltnormalize PRIVATE ${MLT_COMPILE_OPTIONS}) -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltnormalize PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +target_link_libraries(mltnormalize PRIVATE mlt m) -install(TARGETS mltnormalize LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +set_target_properties(mltnormalize PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") + +install(TARGETS mltnormalize LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES filter_audiolevel.yml filter_volume.yml - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/normalize + DESTINATION ${MLT_INSTALL_DATA_DIR}/normalize ) diff --git a/src/modules/normalize/factory.c b/src/modules/normalize/factory.c index cd222de60..7bd19784d 100644 --- a/src/modules/normalize/factory.c +++ b/src/modules/normalize/factory.c @@ -33,8 +33,8 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( filter_type, "audiolevel", filter_audiolevel_init ); - MLT_REGISTER( filter_type, "volume", filter_volume_init ); - MLT_REGISTER_METADATA( filter_type, "audiolevel", metadata, "filter_audiolevel.yml" ); - MLT_REGISTER_METADATA( filter_type, "volume", metadata, "filter_volume.yml" ); + MLT_REGISTER( mlt_service_filter_type, "audiolevel", filter_audiolevel_init ); + MLT_REGISTER( mlt_service_filter_type, "volume", filter_volume_init ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "audiolevel", metadata, "filter_audiolevel.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "volume", metadata, "filter_volume.yml" ); } diff --git a/src/modules/oldfilm/CMakeLists.txt b/src/modules/oldfilm/CMakeLists.txt index 8b3db2c11..d74def2f6 100644 --- a/src/modules/oldfilm/CMakeLists.txt +++ b/src/modules/oldfilm/CMakeLists.txt @@ -8,12 +8,13 @@ add_library(mltoldfilm MODULE filter_vignette.c ) -target_link_libraries(mltoldfilm mlt m) +target_compile_options(mltoldfilm PRIVATE ${MLT_COMPILE_OPTIONS}) -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltoldfilm PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +target_link_libraries(mltoldfilm PRIVATE mlt m) -install(TARGETS mltoldfilm LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +set_target_properties(mltoldfilm PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") + +install(TARGETS mltoldfilm LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES filter_dust.yml @@ -33,5 +34,5 @@ install(FILES oldfilm.svg tcolor.svg vignette.svg - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/oldfilm + DESTINATION ${MLT_INSTALL_DATA_DIR}/oldfilm ) diff --git a/src/modules/oldfilm/factory.c b/src/modules/oldfilm/factory.c index f957c9d61..0e3d8d766 100644 --- a/src/modules/oldfilm/factory.c +++ b/src/modules/oldfilm/factory.c @@ -37,19 +37,19 @@ static mlt_properties oldfilm_metadata( mlt_service_type type, const char *id, v MLT_REPOSITORY { - MLT_REGISTER( filter_type, "oldfilm", filter_oldfilm_init ); - MLT_REGISTER( filter_type, "dust", filter_dust_init ); - MLT_REGISTER( filter_type, "lines", filter_lines_init ); - MLT_REGISTER( filter_type, "grain", filter_grain_init ); - MLT_REGISTER( filter_type, "tcolor", filter_tcolor_init ); - MLT_REGISTER( filter_type, "vignette", filter_vignette_init ); + MLT_REGISTER( mlt_service_filter_type, "oldfilm", filter_oldfilm_init ); + MLT_REGISTER( mlt_service_filter_type, "dust", filter_dust_init ); + MLT_REGISTER( mlt_service_filter_type, "lines", filter_lines_init ); + MLT_REGISTER( mlt_service_filter_type, "grain", filter_grain_init ); + MLT_REGISTER( mlt_service_filter_type, "tcolor", filter_tcolor_init ); + MLT_REGISTER( mlt_service_filter_type, "vignette", filter_vignette_init ); - MLT_REGISTER_METADATA( filter_type, "vignette", oldfilm_metadata, NULL ); - MLT_REGISTER_METADATA( filter_type, "tcolor", oldfilm_metadata, NULL ); - MLT_REGISTER_METADATA( filter_type, "grain", oldfilm_metadata, NULL ); - MLT_REGISTER_METADATA( filter_type, "lines", oldfilm_metadata, NULL ); - MLT_REGISTER_METADATA( filter_type, "dust", oldfilm_metadata, NULL ); - MLT_REGISTER_METADATA( filter_type, "oldfilm", oldfilm_metadata, NULL ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "vignette", oldfilm_metadata, NULL ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "tcolor", oldfilm_metadata, NULL ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "grain", oldfilm_metadata, NULL ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "lines", oldfilm_metadata, NULL ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "dust", oldfilm_metadata, NULL ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "oldfilm", oldfilm_metadata, NULL ); } diff --git a/src/modules/oldfilm/filter_dust.c b/src/modules/oldfilm/filter_dust.c index 138d09430..9d6e04d49 100644 --- a/src/modules/oldfilm/filter_dust.c +++ b/src/modules/oldfilm/filter_dust.c @@ -137,7 +137,14 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format mlt_properties_set( MLT_FRAME_PROPERTIES( luma_frame ), "rescale.interp", "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_mask (luma_frame ); + alpha = mlt_frame_get_alpha( luma_frame ); + if ( !alpha ) + { + int alphasize = luma_width * luma_height; + alpha = mlt_pool_alloc( alphasize ); + memset( alpha, 255, alphasize ); + mlt_frame_set_alpha( luma_frame, alpha, alphasize, mlt_pool_release ); + } uint8_t* savealpha = mlt_pool_alloc( luma_width * luma_height ); uint8_t* savepic = mlt_pool_alloc( luma_width * luma_height * 2); diff --git a/src/modules/opencv/CMakeLists.txt b/src/modules/opencv/CMakeLists.txt index 518f3f073..b9e9b3a25 100644 --- a/src/modules/opencv/CMakeLists.txt +++ b/src/modules/opencv/CMakeLists.txt @@ -1,8 +1,10 @@ add_library(mltopencv MODULE factory.c filter_opencv_tracker.cpp) -target_link_libraries(mltopencv mlt ${OpenCV_LIBS}) -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltopencv PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +target_compile_options(mltopencv PRIVATE ${MLT_COMPILE_OPTIONS}) -install(TARGETS mltopencv LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) -install(FILES filter_opencv_tracker.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/opencv) +target_link_libraries(mltopencv PRIVATE mlt ${OpenCV_LIBS}) + +set_target_properties(mltopencv PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") + +install(TARGETS mltopencv LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) +install(FILES filter_opencv_tracker.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/opencv) diff --git a/src/modules/opencv/factory.c b/src/modules/opencv/factory.c index b3b0ccc30..2bfceed97 100644 --- a/src/modules/opencv/factory.c +++ b/src/modules/opencv/factory.c @@ -33,6 +33,6 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( filter_type, "opencv.tracker", filter_tracker_init ); - MLT_REGISTER_METADATA( filter_type, "opencv.tracker", metadata, "filter_opencv_tracker.yml" ); + MLT_REGISTER( mlt_service_filter_type, "opencv.tracker", filter_tracker_init ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "opencv.tracker", metadata, "filter_opencv_tracker.yml" ); } diff --git a/src/modules/opencv/filter_opencv_tracker.cpp b/src/modules/opencv/filter_opencv_tracker.cpp index 8ec56abe3..9e957ade0 100644 --- a/src/modules/opencv/filter_opencv_tracker.cpp +++ b/src/modules/opencv/filter_opencv_tracker.cpp @@ -44,11 +44,13 @@ typedef struct } private_data; -static void property_changed( mlt_service owner, mlt_filter filter, char *name ) +static void property_changed( mlt_service owner, mlt_filter filter, mlt_event_data event_data ) { private_data* pdata = (private_data*)filter->child; mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); - if ( !strcmp( name, "results" ) ) + const char *name = mlt_event_data_to_string(event_data); + + if ( name && !strcmp( name, "results" ) ) { mlt_properties_anim_get_int( filter_properties, "results", 0, -1 ); mlt_animation anim = mlt_properties_get_animation( filter_properties, "results" ); @@ -313,7 +315,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format } else { - *format = mlt_image_rgb24; + *format = mlt_image_rgb; error = mlt_frame_get_image( frame, image, format, width, height, 1 ); cvFrame = cv::Mat( *height, *width, CV_8UC3, *image ); } diff --git a/src/modules/plus/CMakeLists.txt b/src/modules/plus/CMakeLists.txt index 05e04867c..1141f0ff1 100644 --- a/src/modules/plus/CMakeLists.txt +++ b/src/modules/plus/CMakeLists.txt @@ -3,6 +3,8 @@ add_library(mltplus MODULE factory.c filter_affine.c filter_charcoal.c + filter_chroma_hold.c + filter_chroma.c filter_dynamictext.c filter_dynamic_loudness.c filter_invert.c @@ -13,41 +15,47 @@ add_library(mltplus MODULE filter_pillar_echo.c filter_rgblut.c filter_sepia.c + filter_shape.c filter_spot_remover.c + filter_strobe.c filter_text.c + filter_threshold.c filter_timer.c - filter_strobe.c producer_blipflash.c producer_count.c + producer_pgm.c transition_affine.c ) -target_link_libraries(mltplus mlt m Threads::Threads) +target_compile_options(mltplus PRIVATE ${MLT_COMPILE_OPTIONS}) + +target_link_libraries(mltplus PRIVATE mlt m Threads::Threads) if(TARGET PkgConfig::FFTW) target_sources(mltplus PRIVATE filter_dance.c filter_fft.c) - target_link_libraries(mltplus PkgConfig::FFTW) + target_link_libraries(mltplus PRIVATE PkgConfig::FFTW) target_compile_definitions(mltplus PRIVATE USE_FFTW) - install(FILES filter_dance.yml filter_fft.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/plus) + install(FILES filter_dance.yml filter_fft.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/plus) endif() if(TARGET PkgConfig::libebur128) - target_link_libraries(mltplus PkgConfig::libebur128) + target_link_libraries(mltplus PRIVATE PkgConfig::libebur128) else() target_sources(mltplus PRIVATE ebur128/ebur128.c) target_include_directories(mltplus PRIVATE ebur128 ebur128/queue) target_compile_definitions(mltplus PRIVATE USE_INTERNAL_LIBEBUR128) endif() -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltplus PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +set_target_properties(mltplus PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(TARGETS mltplus LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +install(TARGETS mltplus LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES consumer_blipflash.yml filter_affine.yml filter_charcoal.yml + filter_chroma_hold.yml + filter_chroma.yml filter_dynamic_loudness.yml filter_dynamictext.yml filter_invert.yml @@ -58,12 +66,15 @@ install(FILES filter_pillar_echo.yml filter_rgblut.yml filter_sepia.yml + filter_shape.yml filter_spot_remover.yml filter_strobe.yml filter_text.yml + filter_threshold.yml filter_timer.yml producer_blipflash.yml producer_count.yml + producer_pgm.yml transition_affine.yml - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/plus + DESTINATION ${MLT_INSTALL_DATA_DIR}/plus ) diff --git a/src/modules/plus/Makefile b/src/modules/plus/Makefile index e5643d884..2f9de7ea2 100644 --- a/src/modules/plus/Makefile +++ b/src/modules/plus/Makefile @@ -11,6 +11,8 @@ OBJS = consumer_blipflash.o \ factory.o \ filter_affine.o \ filter_charcoal.o \ + filter_chroma.o \ + filter_chroma_hold.o \ filter_dynamictext.o \ filter_dynamic_loudness.o \ filter_invert.o \ @@ -23,10 +25,13 @@ OBJS = consumer_blipflash.o \ filter_sepia.o \ filter_spot_remover.o \ filter_text.o \ + filter_threshold.o \ filter_timer.o \ + filter_shape.o \ filter_strobe.o \ producer_blipflash.o \ producer_count.o \ + producer_pgm.o \ transition_affine.o ifdef USE_FFTW diff --git a/src/modules/plus/consumer_blipflash.c b/src/modules/plus/consumer_blipflash.c index 7414df7fb..3595d91c2 100644 --- a/src/modules/plus/consumer_blipflash.c +++ b/src/modules/plus/consumer_blipflash.c @@ -1,8 +1,7 @@ /* * consumer_blipflash.c -- a consumer to measure A/V sync from a blip/flash * source - * Copyright (C) 2013 Brian Matherly - * Author: Brian Matherly + * Copyright (C) 2013 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -387,7 +386,7 @@ static void *consumer_thread( void *arg ) report_results( stats, pos ); // Close the frame - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); mlt_frame_close( frame ); } } diff --git a/src/modules/plus/consumer_blipflash.yml b/src/modules/plus/consumer_blipflash.yml index 5c8f40e50..56e933d1c 100644 --- a/src/modules/plus/consumer_blipflash.yml +++ b/src/modules/plus/consumer_blipflash.yml @@ -3,8 +3,7 @@ type: consumer identifier: blipflash title: Blip Flash version: 1 -copyright: Brian Matherly -creator: Brian Matherly +copyright: Meltytech, LLC license: LGPLv2.1 language: en tags: diff --git a/src/modules/plus/factory.c b/src/modules/plus/factory.c index 26e4eafac..d139e4ecd 100644 --- a/src/modules/plus/factory.c +++ b/src/modules/plus/factory.c @@ -24,22 +24,27 @@ extern mlt_consumer consumer_blipflash_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_affine_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_charcoal_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +extern mlt_filter filter_chroma_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +extern mlt_filter filter_chroma_hold_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_dynamictext_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_dynamic_loudness_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +extern mlt_filter filter_invert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_lift_gamma_gain_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); 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_invert_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 ); extern mlt_filter filter_spot_remover_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +extern mlt_filter filter_strobe_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_text_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +extern mlt_filter filter_threshold_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_timer_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -extern mlt_filter filter_strobe_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_blipflash_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_producer producer_count_init( const char *arg ); +extern mlt_producer producer_pgm_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_transition transition_affine_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); #ifdef USE_FFTW @@ -56,53 +61,63 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( consumer_type, "blipflash", consumer_blipflash_init ); - MLT_REGISTER( filter_type, "affine", filter_affine_init ); - MLT_REGISTER( filter_type, "charcoal", filter_charcoal_init ); - MLT_REGISTER( filter_type, "dynamictext", filter_dynamictext_init ); - MLT_REGISTER( filter_type, "dynamic_loudness", filter_dynamic_loudness_init ); - MLT_REGISTER( filter_type, "invert", filter_invert_init ); - MLT_REGISTER( filter_type, "lift_gamma_gain", filter_lift_gamma_gain_init ); - MLT_REGISTER( filter_type, "loudness", filter_loudness_init ); - MLT_REGISTER( filter_type, "loudness_meter", filter_loudness_meter_init ); - MLT_REGISTER( filter_type, "lumakey", filter_lumakey_init ); - MLT_REGISTER( filter_type, "pillar_echo", filter_pillar_echo_init ); - MLT_REGISTER( filter_type, "rgblut", filter_rgblut_init ); - MLT_REGISTER( filter_type, "sepia", filter_sepia_init ); - MLT_REGISTER( filter_type, "spot_remover", filter_spot_remover_init ); - MLT_REGISTER( filter_type, "text", filter_text_init ); - MLT_REGISTER( filter_type, "timer", filter_timer_init ); - MLT_REGISTER( filter_type, "strobe", filter_strobe_init ); - MLT_REGISTER( producer_type, "blipflash", producer_blipflash_init ); - MLT_REGISTER( producer_type, "count", producer_count_init ); - MLT_REGISTER( transition_type, "affine", transition_affine_init ); + MLT_REGISTER( mlt_service_consumer_type, "blipflash", consumer_blipflash_init ); + MLT_REGISTER( mlt_service_filter_type, "affine", filter_affine_init ); + MLT_REGISTER( mlt_service_filter_type, "charcoal", filter_charcoal_init ); + MLT_REGISTER( mlt_service_filter_type, "chroma", filter_chroma_init ); + MLT_REGISTER( mlt_service_filter_type, "chroma_hold", filter_chroma_hold_init ); + MLT_REGISTER( mlt_service_filter_type, "dynamictext", filter_dynamictext_init ); + MLT_REGISTER( mlt_service_filter_type, "dynamic_loudness", filter_dynamic_loudness_init ); + MLT_REGISTER( mlt_service_filter_type, "invert", filter_invert_init ); + MLT_REGISTER( mlt_service_filter_type, "lift_gamma_gain", filter_lift_gamma_gain_init ); + 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 ); + MLT_REGISTER( mlt_service_filter_type, "spot_remover", filter_spot_remover_init ); + MLT_REGISTER( mlt_service_filter_type, "strobe", filter_strobe_init ); + MLT_REGISTER( mlt_service_filter_type, "text", filter_text_init ); + MLT_REGISTER( mlt_service_filter_type, "threshold", filter_threshold_init ); + MLT_REGISTER( mlt_service_filter_type, "timer", filter_timer_init ); + MLT_REGISTER( mlt_service_producer_type, "blipflash", producer_blipflash_init ); + MLT_REGISTER( mlt_service_producer_type, "count", producer_count_init ); + MLT_REGISTER( mlt_service_producer_type, "pgm", producer_pgm_init ); + MLT_REGISTER( mlt_service_transition_type, "affine", transition_affine_init ); #ifdef USE_FFTW - MLT_REGISTER( filter_type, "dance", filter_dance_init ); - MLT_REGISTER( filter_type, "fft", filter_fft_init ); + MLT_REGISTER( mlt_service_filter_type, "dance", filter_dance_init ); + MLT_REGISTER( mlt_service_filter_type, "fft", filter_fft_init ); #endif - MLT_REGISTER_METADATA( consumer_type, "blipflash", metadata, "consumer_blipflash.yml" ); - MLT_REGISTER_METADATA( filter_type, "affine", metadata, "filter_affine.yml" ); - MLT_REGISTER_METADATA( filter_type, "charcoal", metadata, "filter_charcoal.yml" ); - MLT_REGISTER_METADATA( filter_type, "dynamictext", metadata, "filter_dynamictext.yml" ); - MLT_REGISTER_METADATA( filter_type, "dynamic_loudness", metadata, "filter_dynamic_loudness.yml" ); - MLT_REGISTER_METADATA( filter_type, "invert", metadata, "filter_invert.yml" ); - MLT_REGISTER_METADATA( filter_type, "lift_gamma_gain", metadata, "filter_lift_gamma_gain.yml" ); - MLT_REGISTER_METADATA( filter_type, "loudness", metadata, "filter_loudness.yml" ); - MLT_REGISTER_METADATA( filter_type, "loudness_meter", metadata, "filter_loudness_meter.yml" ); - MLT_REGISTER_METADATA( filter_type, "lumakey", metadata, "filter_lumakey.yml" ); - MLT_REGISTER_METADATA( filter_type, "pillar_echo", metadata, "filter_pillar_echo.yml" ); - MLT_REGISTER_METADATA( filter_type, "rgblut", metadata, "filter_rgblut.yml" ); - MLT_REGISTER_METADATA( filter_type, "sepia", metadata, "filter_sepia.yml" ); - MLT_REGISTER_METADATA( filter_type, "spot_remover", metadata, "filter_spot_remover.yml" ); - MLT_REGISTER_METADATA( filter_type, "text", metadata, "filter_text.yml" ); - MLT_REGISTER_METADATA( filter_type, "timer", metadata, "filter_timer.yml" ); - MLT_REGISTER_METADATA( filter_type, "strobe", metadata, "filter_strobe.yml" ); - MLT_REGISTER_METADATA( producer_type, "blipflash", metadata, "producer_blipflash.yml" ); - MLT_REGISTER_METADATA( producer_type, "count", metadata, "producer_count.yml" ); - MLT_REGISTER_METADATA( transition_type, "affine", metadata, "transition_affine.yml" ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "blipflash", metadata, "consumer_blipflash.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "affine", metadata, "filter_affine.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "charcoal", metadata, "filter_charcoal.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "chroma", metadata, "filter_chroma.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "chroma_hold", metadata, "filter_chroma_hold.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "dynamictext", metadata, "filter_dynamictext.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "dynamic_loudness", metadata, "filter_dynamic_loudness.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "invert", metadata, "filter_invert.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "lift_gamma_gain", metadata, "filter_lift_gamma_gain.yml" ); + 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" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "spot_remover", metadata, "filter_spot_remover.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "strobe", metadata, "filter_strobe.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "text", metadata, "filter_text.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "threshold", metadata, "filter_threshold.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "timer", metadata, "filter_timer.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "blipflash", metadata, "producer_blipflash.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "count", metadata, "producer_count.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "pgm", metadata, "producer_pgm.yml" ); + MLT_REGISTER_METADATA( mlt_service_transition_type, "affine", metadata, "transition_affine.yml" ); #ifdef USE_FFTW - MLT_REGISTER_METADATA( filter_type, "dance", metadata, "filter_dance.yml" ); - MLT_REGISTER_METADATA( filter_type, "fft", metadata, "filter_fft.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "dance", metadata, "filter_dance.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "fft", metadata, "filter_fft.yml" ); #endif } diff --git a/src/modules/plus/filter_affine.c b/src/modules/plus/filter_affine.c index bade559bf..b6eebf9e3 100644 --- a/src/modules/plus/filter_affine.c +++ b/src/modules/plus/filter_affine.c @@ -1,6 +1,6 @@ /* * filter_affine.c -- affine filter - * Copyright (C) 2003-2020 Meltytech, LLC + * Copyright (C) 2003-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 @@ -40,7 +40,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format // Get the image int error = 0; - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); @@ -111,7 +111,10 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format mlt_frame_get_image( a_frame, image, format, width, height, writable ); mlt_properties_set_data( frame_properties, "affine_frame", a_frame, 0, (mlt_destructor)mlt_frame_close, NULL ); mlt_frame_set_image( frame, *image, *width * *height * 4, NULL ); - mlt_frame_set_alpha( frame, mlt_frame_get_alpha_mask( a_frame ), *width * *height, NULL ); + uint8_t* alpha = mlt_frame_get_alpha( a_frame ); + if ( alpha ) { + mlt_frame_set_alpha( frame, alpha, *width * *height, NULL ); + } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); } else diff --git a/src/modules/vmfx/filter_chroma.c b/src/modules/plus/filter_chroma.c similarity index 90% rename from src/modules/vmfx/filter_chroma.c rename to src/modules/plus/filter_chroma.c index c49c3a600..558f5fdb0 100644 --- a/src/modules/vmfx/filter_chroma.c +++ b/src/modules/plus/filter_chroma.c @@ -1,6 +1,7 @@ /* * filter_chroma.c -- Maps a chroma key to the alpha channel * Copyright (C) 2005 Visual Media Fx Inc. + * Copyright (C) 2021 Meltytech, LLC * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify @@ -19,11 +20,13 @@ */ #include -#include #include #include #include +#include +#include + static inline int in_range( uint8_t v, uint8_t c, int var ) { return ( ( int )v >= c - var ) && ( ( int )v <= c + var ); @@ -55,7 +58,14 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format = mlt_image_yuv422; if ( mlt_frame_get_image( frame, image, format, width, height, writable ) == 0 ) { - uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); + uint8_t *alpha = mlt_frame_get_alpha( frame ); + if ( !alpha ) + { + int alphasize = *width * *height; + alpha = mlt_pool_alloc( alphasize ); + memset( alpha, 255, alphasize ); + mlt_frame_set_alpha( frame, alpha, alphasize, mlt_pool_release ); + } uint8_t *p = *image; int size = *width * *height / 2; while ( size -- ) diff --git a/src/modules/vmfx/filter_chroma.yml b/src/modules/plus/filter_chroma.yml similarity index 100% rename from src/modules/vmfx/filter_chroma.yml rename to src/modules/plus/filter_chroma.yml diff --git a/src/modules/vmfx/filter_chroma_hold.c b/src/modules/plus/filter_chroma_hold.c similarity index 100% rename from src/modules/vmfx/filter_chroma_hold.c rename to src/modules/plus/filter_chroma_hold.c diff --git a/src/modules/vmfx/filter_chroma_hold.yml b/src/modules/plus/filter_chroma_hold.yml similarity index 100% rename from src/modules/vmfx/filter_chroma_hold.yml rename to src/modules/plus/filter_chroma_hold.yml diff --git a/src/modules/plus/filter_dance.yml b/src/modules/plus/filter_dance.yml index 3368390e9..4f89ad398 100644 --- a/src/modules/plus/filter_dance.yml +++ b/src/modules/plus/filter_dance.yml @@ -4,7 +4,6 @@ identifier: dance title: Dance version: 1 copyright: Meltytech, LLC -creator: Brian Matherly license: LGPLv2.1 language: en tags: diff --git a/src/modules/plus/filter_dynamic_loudness.c b/src/modules/plus/filter_dynamic_loudness.c index 99c830514..932817e4a 100644 --- a/src/modules/plus/filter_dynamic_loudness.c +++ b/src/modules/plus/filter_dynamic_loudness.c @@ -1,7 +1,6 @@ /* * filter_loudness.c -- normalize audio according to EBU R128 - * Copyright (C) 2014 Brian Matherly - * Author: Brian Matherly + * Copyright (C) 2014 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -35,10 +34,11 @@ typedef struct mlt_position prev_o_pos; } private_data; -static void property_changed( mlt_service owner, mlt_filter filter, char *name ) +static void property_changed( mlt_service owner, mlt_filter filter, mlt_event_data event_data ) { + const char *name = mlt_event_data_to_string(event_data); private_data* pdata = (private_data*)filter->child; - if ( !strcmp( name, "window" ) ) + if ( name && pdata && !strcmp( name, "window" ) ) { pdata->reset = 1; } diff --git a/src/modules/plus/filter_dynamic_loudness.yml b/src/modules/plus/filter_dynamic_loudness.yml index 83b865040..cf990e0a2 100644 --- a/src/modules/plus/filter_dynamic_loudness.yml +++ b/src/modules/plus/filter_dynamic_loudness.yml @@ -3,8 +3,7 @@ type: filter identifier: dynamic_loudness title: Dynamic Loudness version: 1 -copyright: Brian Matherly -creator: Brian Matherly +copyright: Meltytech, LLC license: LGPLv2.1 language: en tags: diff --git a/src/modules/plus/filter_dynamictext.yml b/src/modules/plus/filter_dynamictext.yml index 51c1d8682..ff9890e00 100644 --- a/src/modules/plus/filter_dynamictext.yml +++ b/src/modules/plus/filter_dynamictext.yml @@ -4,7 +4,6 @@ identifier: dynamictext title: Dynamic text version: 1 copyright: Meltytech, LLC -creator: Brian Matherly license: LGPLv2.1 language: en tags: diff --git a/src/modules/plus/filter_fft.yml b/src/modules/plus/filter_fft.yml index 0b6f9c9a8..e529fb40e 100644 --- a/src/modules/plus/filter_fft.yml +++ b/src/modules/plus/filter_fft.yml @@ -4,7 +4,6 @@ identifier: fft title: FFT version: 1 copyright: Meltytech, LLC -creator: Brian Matherly license: LGPLv2.1 language: en tags: diff --git a/src/modules/plus/filter_invert.c b/src/modules/plus/filter_invert.c index 31599e9ea..34e2ccff8 100644 --- a/src/modules/plus/filter_invert.c +++ b/src/modules/plus/filter_invert.c @@ -57,9 +57,10 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format if ( mask ) { - uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); int size = *width * *height; + uint8_t* alpha = mlt_pool_alloc( size ); memset( alpha, mask, size ); + mlt_frame_set_alpha( frame, alpha, size, mlt_pool_release ); } } diff --git a/src/modules/plus/filter_lift_gamma_gain.c b/src/modules/plus/filter_lift_gamma_gain.c index 6d79ae27a..29b29157c 100644 --- a/src/modules/plus/filter_lift_gamma_gain.c +++ b/src/modules/plus/filter_lift_gamma_gain.c @@ -1,6 +1,6 @@ /* * filter_lift_gamma_gain.cpp - * Copyright (C) 2014 Brian Matherly + * Copyright (C) 2014 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -125,7 +125,7 @@ static void apply_lut( mlt_filter filter, uint8_t* image, mlt_image_format forma switch( format ) { - case mlt_image_rgb24: + case mlt_image_rgb: while( --total ) { *sample = rlut[ *sample ]; @@ -136,7 +136,7 @@ static void apply_lut( mlt_filter filter, uint8_t* image, mlt_image_format forma sample++; } break; - case mlt_image_rgb24a: + case mlt_image_rgba: while( --total ) { *sample = rlut[ *sample ]; @@ -169,9 +169,9 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); // Make sure the format is acceptable - if( *format != mlt_image_rgb24 && *format != mlt_image_rgb24a ) + if( *format != mlt_image_rgb && *format != mlt_image_rgba ) { - *format = mlt_image_rgb24; + *format = mlt_image_rgb; } // Get the image diff --git a/src/modules/plus/filter_lift_gamma_gain.yml b/src/modules/plus/filter_lift_gamma_gain.yml index a4a3be3ab..6d989d37d 100644 --- a/src/modules/plus/filter_lift_gamma_gain.yml +++ b/src/modules/plus/filter_lift_gamma_gain.yml @@ -3,8 +3,7 @@ type: filter identifier: lift_gamma_gain title: Lift, Gamma, and Gain version: 1 -copyright: Brian Matherly -creator: Brian Matherly +copyright: Meltytech, LLC license: LGPLv2.1 language: en tags: diff --git a/src/modules/plus/filter_loudness.c b/src/modules/plus/filter_loudness.c index 0614fecc3..3612b586a 100644 --- a/src/modules/plus/filter_loudness.c +++ b/src/modules/plus/filter_loudness.c @@ -1,7 +1,6 @@ /* * filter_loudness.c -- normalize audio according to EBU R128 - * Copyright (C) 2014 Brian Matherly - * Author: Brian Matherly + * Copyright (C) 2014 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/modules/plus/filter_loudness.yml b/src/modules/plus/filter_loudness.yml index 7c935b4e6..c7da8ff4e 100644 --- a/src/modules/plus/filter_loudness.yml +++ b/src/modules/plus/filter_loudness.yml @@ -3,8 +3,7 @@ type: filter identifier: loudness title: Loudness version: 1 -copyright: Brian Matherly -creator: Brian Matherly +copyright: Meltytech, LLC license: LGPLv2.1 language: en tags: diff --git a/src/modules/plus/filter_loudness_meter.c b/src/modules/plus/filter_loudness_meter.c index 6c81d19f7..bcd720fa1 100644 --- a/src/modules/plus/filter_loudness_meter.c +++ b/src/modules/plus/filter_loudness_meter.c @@ -1,7 +1,6 @@ /* * filter_loudness_meter.c -- measure audio loudness according to EBU R128 - * Copyright (C) 2016 Brian Matherly - * Author: Brian Matherly + * Copyright (C) 2016 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -31,16 +30,17 @@ typedef struct mlt_position prev_pos; } private_data; -static void property_changed( mlt_service owner, mlt_filter filter, char *name ) +static void property_changed( mlt_service owner, mlt_filter filter, mlt_event_data event_data ) { + const char *name = mlt_event_data_to_string(event_data); private_data* pdata = (private_data*)filter->child; - if ( !strcmp( name, "reset" ) || + if ( name && pdata && ( !strcmp( name, "reset" ) || !strcmp( name, "calc_program" ) || !strcmp( name, "calc_shortterm" ) || !strcmp( name, "calc_momentary" ) || !strcmp( name, "calc_range" ) || !strcmp( name, "calc_peak" ) || - !strcmp( name, "calc_true_peak" ) ) + !strcmp( name, "calc_true_peak" ) ) ) { pdata->reset = 1; } diff --git a/src/modules/plus/filter_loudness_meter.yml b/src/modules/plus/filter_loudness_meter.yml index e6078af9e..6f4838618 100644 --- a/src/modules/plus/filter_loudness_meter.yml +++ b/src/modules/plus/filter_loudness_meter.yml @@ -3,8 +3,7 @@ type: filter identifier: loudness_meter title: Loudness Meter version: 1 -copyright: Brian Matherly -creator: Brian Matherly +copyright: Meltytech, LLC license: LGPLv2.1 language: en tags: diff --git a/src/modules/plus/filter_lumakey.c b/src/modules/plus/filter_lumakey.c index be724d196..987a7c551 100644 --- a/src/modules/plus/filter_lumakey.c +++ b/src/modules/plus/filter_lumakey.c @@ -69,7 +69,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; int error = mlt_frame_get_image( frame, image, format, width, height, 0 ); // Only process if we have no error and a valid colour space diff --git a/src/modules/plus/filter_pillar_echo.c b/src/modules/plus/filter_pillar_echo.c index 9ddf528d0..31c6916fb 100644 --- a/src/modules/plus/filter_pillar_echo.c +++ b/src/modules/plus/filter_pillar_echo.c @@ -1,6 +1,6 @@ /* * filter_pillar_echo.c -- filter to interpolate pixels outside an area of interest - * Copyright (c) 2020 Meltytech, LLC + * 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 @@ -107,7 +107,6 @@ static void bilinear_scale_rgba( uint8_t* src, uint8_t* dst, int width, int heig double factorSum[] = {0.0, 0.0, 0.0, 0.0}; uint8_t* s = src + (srcYindex * linesize) + (srcXindex * 4); - uint8_t* st = s; // Top Left double ftl = ftop * fleft; @@ -396,7 +395,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format return mlt_frame_get_image( frame, image, format, width, height, writable ); } - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; error = mlt_frame_get_image( frame, image, format, width, height, 1 ); if (error) return error; diff --git a/src/modules/plus/filter_rgblut.c b/src/modules/plus/filter_rgblut.c index 3f268d472..41c598423 100644 --- a/src/modules/plus/filter_rgblut.c +++ b/src/modules/plus/filter_rgblut.c @@ -65,7 +65,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format // Get the image mlt_filter filter = mlt_frame_pop_service( frame ); - *format = mlt_image_rgb24; + *format = mlt_image_rgb; int error = mlt_frame_get_image( frame, image, format, width, height, 0 ); // Only process if we have no error and a valid colour space diff --git a/src/modules/vmfx/filter_shape.c b/src/modules/plus/filter_shape.c similarity index 93% rename from src/modules/vmfx/filter_shape.c rename to src/modules/plus/filter_shape.c index 824a165e6..6209cebbb 100644 --- a/src/modules/vmfx/filter_shape.c +++ b/src/modules/plus/filter_shape.c @@ -1,6 +1,7 @@ /* * filter_shape.c -- Arbitrary alpha channel shaping * Copyright (C) 2005 Visual Media Fx Inc. + * Copyright (C) 2021 Meltytech, LLC * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify @@ -59,9 +60,6 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format if ( mlt_frame_get_image( frame, image, format, width, height, writable ) == 0 && ( !use_luminance || !use_mix || (int) mix != 1 || invert == 255 ) ) { - // Get the alpha mask of the source - uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); - // Obtain a scaled/distorted mask to match uint8_t *mask_img = NULL; mlt_image_format mask_fmt = mlt_image_yuv422; @@ -71,12 +69,27 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format if ( mlt_frame_get_image( mask, &mask_img, &mask_fmt, width, height, 0 ) == 0 ) { int size = *width * *height; - uint8_t *p = alpha; double a = 0; double b = 0; + uint8_t* p = mlt_frame_get_alpha( frame ); + if ( !p ) + { + int alphasize = *width * *height; + p = mlt_pool_alloc( alphasize ); + memset( p, 255, alphasize ); + mlt_frame_set_alpha( frame, p, alphasize, mlt_pool_release ); + } + if ( !use_luminance ) { - uint8_t *q = mlt_frame_get_alpha_mask( mask ); + uint8_t* q = mlt_frame_get_alpha( mask ); + if ( !q ) + { + int alphasize = *width * *height; + q = mlt_pool_alloc( alphasize ); + memset( q, 255, alphasize ); + mlt_frame_set_alpha( mask, q, alphasize, mlt_pool_release ); + } if ( use_mix ) { while( size -- ) diff --git a/src/modules/vmfx/filter_shape.yml b/src/modules/plus/filter_shape.yml similarity index 100% rename from src/modules/vmfx/filter_shape.yml rename to src/modules/plus/filter_shape.yml diff --git a/src/modules/plus/filter_spot_remover.c b/src/modules/plus/filter_spot_remover.c index dedb63d20..c03813c78 100644 --- a/src/modules/plus/filter_spot_remover.c +++ b/src/modules/plus/filter_spot_remover.c @@ -155,60 +155,63 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format switch( *format ) { - case mlt_image_rgb24a: - case mlt_image_rgb24: + case mlt_image_rgba: + case mlt_image_rgb: case mlt_image_yuv422: case mlt_image_yuv420p: // These formats are all supported break; default: - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; break; } error = mlt_frame_get_image( frame, image, format, width, height, 1 ); if (error) return error; + struct mlt_image_s img; + mlt_image_set_values( &img, *image, *format, *width, *height ); + int i; switch( *format ) { - case mlt_image_rgb24a: + case mlt_image_rgba: for ( i = 0; i < 4; i++ ) { - remove_spot_channel( *image + i, *width, 4, rect ); + remove_spot_channel( img.planes[0] + i, img.width, 4, rect ); } break; - case mlt_image_rgb24: + case mlt_image_rgb: for ( i = 0; i < 3; i++ ) { - remove_spot_channel( *image + i, *width, 3, rect ); + remove_spot_channel( img.planes[0] + i, img.width, 3, rect ); } break; case mlt_image_yuv422: // Y - remove_spot_channel( *image, *width, 2, rect ); + remove_spot_channel( img.planes[0], img.width, 2, rect ); // U - remove_spot_channel( *image + 1, *width / 2, 4, - constrain_rect( scale_rect( rect, 2, 1 ), *width / 2, *height ) ); + remove_spot_channel( img.planes[0] + 1, img.width / 2, 4, + constrain_rect( scale_rect( rect, 2, 1 ), img.width / 2, img.height ) ); // V - remove_spot_channel( *image + 3, *width / 2, 4, - constrain_rect( scale_rect( rect, 2, 1 ), *width / 2, *height ) ); + remove_spot_channel( img.planes[0] + 3, img.width / 2, 4, + constrain_rect( scale_rect( rect, 2, 1 ), img.width / 2, img.height ) ); break; case mlt_image_yuv420p: // Y - remove_spot_channel( *image, *width, 1, rect ); + remove_spot_channel( img.planes[0], img.width, 1, rect ); // U - remove_spot_channel( *image + (*width * *height), *width / 2, 1, - constrain_rect( scale_rect( rect, 2, 2 ), *width / 2, *height / 2 ) ); + remove_spot_channel( img.planes[1], img.width / 2, 1, + constrain_rect( scale_rect( rect, 2, 2 ), img.width / 2, img.height / 2 ) ); // V - remove_spot_channel( *image + (*width * *height * 5 / 4), *width / 2, 1, - constrain_rect( scale_rect( rect, 2, 2 ), *width / 2, *height / 2 ) ); + remove_spot_channel( img.planes[2], img.width / 2, 1, + constrain_rect( scale_rect( rect, 2, 2 ), img.width / 2, img.height / 2 ) ); break; default: return 1; } uint8_t *alpha = mlt_frame_get_alpha( frame ); - if ( alpha && *format != mlt_image_rgb24a ) + if ( alpha && *format != mlt_image_rgba ) { remove_spot_channel( alpha, *width, 1, rect ); } diff --git a/src/modules/plus/filter_spot_remover.yml b/src/modules/plus/filter_spot_remover.yml index dc07c8d7e..a427fec73 100644 --- a/src/modules/plus/filter_spot_remover.yml +++ b/src/modules/plus/filter_spot_remover.yml @@ -4,7 +4,6 @@ identifier: spot_remover title: Spot Remover version: 1 copyright: Meltytech, LLC -creator: Brian Matherly license: LGPLv2.1 language: en tags: diff --git a/src/modules/plus/filter_strobe.c b/src/modules/plus/filter_strobe.c index f00abff8d..a78cd0d9f 100644 --- a/src/modules/plus/filter_strobe.c +++ b/src/modules/plus/filter_strobe.c @@ -61,25 +61,21 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format assert( *height >= 0 ); size_t pixelCount = *width * *height; - // We always clear the alpha mask, in case there's some optimizations - // that can be applied or other filters modyify the image contents. - uint8_t *alpha_buffer = mlt_frame_get_alpha_mask( frame ); - assert( alpha_buffer != NULL ); - - // We assert because the API contract guarantees that we always get a - // buffer, but don't want to crash in release build if it is broken. - if ( alpha_buffer ) - { - memset( alpha_buffer, 0, pixelCount ); - } - - if ( *format == mlt_image_rgb24a ) + if ( *format == mlt_image_rgba ) { uint8_t *bytes = *image; for ( size_t i=3; i #include -static void property_changed( mlt_service owner, mlt_filter filter, char *name ) +static void property_changed( mlt_service owner, mlt_filter filter, mlt_event_data event_data ) { + const char *name = mlt_event_data_to_string(event_data); + if (!name) return; if( !strcmp( "geometry", name ) || !strcmp( "family", name ) || !strcmp( "size", name ) || diff --git a/src/modules/plus/filter_text.yml b/src/modules/plus/filter_text.yml index aefaca002..85f104dea 100644 --- a/src/modules/plus/filter_text.yml +++ b/src/modules/plus/filter_text.yml @@ -4,7 +4,6 @@ identifier: text title: Text version: 1 copyright: Meltytech, LLC -creator: Brian Matherly license: LGPLv2.1 language: en tags: diff --git a/src/modules/vmfx/filter_mono.c b/src/modules/plus/filter_threshold.c similarity index 86% rename from src/modules/vmfx/filter_mono.c rename to src/modules/plus/filter_threshold.c index fd030a820..2d4f87530 100644 --- a/src/modules/vmfx/filter_mono.c +++ b/src/modules/plus/filter_threshold.c @@ -1,6 +1,7 @@ /* - * filter_mono.c -- Arbitrary alpha channel shaping + * filter_threshold.c -- Arbitrary alpha channel shaping * Copyright (C) 2005 Visual Media Fx Inc. + * Copyright (C) 2021 Meltytech, LLC * Author: Charles Yates * * This program is free software; you can redistribute it and/or modify @@ -62,14 +63,25 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format } else { - uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); - while (--size) + uint8_t *alpha = mlt_frame_get_alpha( frame ); + if ( alpha ) { - if ( *alpha ++ < midpoint ) - *p ++ = A; - else + while (--size) + { + if ( *alpha ++ < midpoint ) + *p ++ = A; + else + *p ++ = B; + *p ++ = 128; + } + } + else + { + while (--size) + { *p ++ = B; - *p ++ = 128; + *p ++ = 128; + } } } } @@ -90,7 +102,7 @@ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) /** Constructor for the filter. */ -mlt_filter filter_mono_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) +mlt_filter filter_threshold_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { mlt_filter filter = mlt_filter_new( ); if ( filter != NULL ) diff --git a/src/modules/vmfx/filter_mono.yml b/src/modules/plus/filter_threshold.yml similarity index 100% rename from src/modules/vmfx/filter_mono.yml rename to src/modules/plus/filter_threshold.yml diff --git a/src/modules/plus/filter_timer.yml b/src/modules/plus/filter_timer.yml index 47d09a1fb..d803bfb30 100644 --- a/src/modules/plus/filter_timer.yml +++ b/src/modules/plus/filter_timer.yml @@ -4,7 +4,6 @@ identifier: timer title: Timer version: 1 copyright: Meltytech, LLC -creator: Brian Matherly license: LGPLv2.1 language: en tags: diff --git a/src/modules/plus/producer_blipflash.c b/src/modules/plus/producer_blipflash.c index 023d33109..7bb4b1ba1 100644 --- a/src/modules/plus/producer_blipflash.c +++ b/src/modules/plus/producer_blipflash.c @@ -1,7 +1,6 @@ /* * producer_blipflash.c -- blip/flash generating producer - * Copyright (C) 2013 Brian Matherly - * Author: Brian Matherly + * Copyright (C) 2013 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -160,7 +159,7 @@ static void fill_image( mlt_properties producer_properties, char* color, uint8_t } break; } - case mlt_image_rgb24: + case mlt_image_rgb: { int i = width * height + 1; while ( --i ) @@ -171,7 +170,7 @@ static void fill_image( mlt_properties producer_properties, char* color, uint8_t } break; } - case mlt_image_rgb24a: + case mlt_image_rgba: { int i = width * height + 1; while ( --i ) @@ -205,7 +204,7 @@ static int producer_get_image( mlt_frame frame, uint8_t** buffer, mlt_image_form mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); // Correct the returns if necessary - if( *format != mlt_image_yuv422 && *format != mlt_image_rgb24 && *format != mlt_image_rgb24a ) + if( *format != mlt_image_yuv422 && *format != mlt_image_rgb && *format != mlt_image_rgba ) *format = mlt_image_yuv422; if( *width <= 0 ) *width = mlt_service_profile( MLT_PRODUCER_SERVICE(producer) )->width; diff --git a/src/modules/plus/producer_blipflash.yml b/src/modules/plus/producer_blipflash.yml index 8bec5a3f0..8b6f4e158 100644 --- a/src/modules/plus/producer_blipflash.yml +++ b/src/modules/plus/producer_blipflash.yml @@ -3,8 +3,7 @@ type: producer identifier: blipflash title: Blip Flash version: 1 -copyright: Brian Matherly -creator: Brian Matherly +copyright: Meltytech, LLC license: LGPLv2.1 language: en tags: diff --git a/src/modules/plus/producer_count.c b/src/modules/plus/producer_count.c index 6cd9bc753..2f9c42120 100644 --- a/src/modules/plus/producer_count.c +++ b/src/modules/plus/producer_count.c @@ -1,7 +1,6 @@ /* * producer_count.c -- counting producer - * Copyright (C) 2013 Brian Matherly - * Author: Brian Matherly + * Copyright (C) 2013 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -477,7 +476,7 @@ static void add_clock_to_frame( mlt_producer producer, mlt_frame frame, time_inf mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); uint8_t* image = NULL; - mlt_image_format format = mlt_image_rgb24a; + mlt_image_format format = mlt_image_rgba; int size = 0; int width = profile->width; int height = profile->height; diff --git a/src/modules/plus/producer_count.yml b/src/modules/plus/producer_count.yml index 4cd906844..024ce7779 100644 --- a/src/modules/plus/producer_count.yml +++ b/src/modules/plus/producer_count.yml @@ -3,8 +3,7 @@ type: producer identifier: count title: Count version: 1 -copyright: Brian Matherly -creator: Brian Matherly +copyright: Meltytech, LLC license: LGPLv2.1 language: en tags: diff --git a/src/modules/vmfx/producer_pgm.c b/src/modules/plus/producer_pgm.c similarity index 100% rename from src/modules/vmfx/producer_pgm.c rename to src/modules/plus/producer_pgm.c diff --git a/src/modules/vmfx/producer_pgm.yml b/src/modules/plus/producer_pgm.yml similarity index 100% rename from src/modules/vmfx/producer_pgm.yml rename to src/modules/plus/producer_pgm.yml diff --git a/src/modules/plus/transition_affine.c b/src/modules/plus/transition_affine.c index 9abccd2d2..0fc24baf5 100644 --- a/src/modules/plus/transition_affine.c +++ b/src/modules/plus/transition_affine.c @@ -78,83 +78,6 @@ static double anim_get_angle(mlt_properties properties, const char* name, mlt_po return result; } -/** Calculate real geometry. -*/ - -static void geometry_calculate( mlt_transition transition, const char *store, struct mlt_geometry_item_s *output, double position ) -{ - mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); - mlt_geometry geometry = mlt_properties_get_data( properties, store, NULL ); - int mirror_off = mlt_properties_get_int( properties, "mirror_off" ); - int repeat_off = mlt_properties_get_int( properties, "repeat_off" ); - int length = mlt_geometry_get_length( geometry ); - - // Allow wrapping - if ( !repeat_off && position >= length && length != 0 ) - { - int section = position / length; - position -= section * length; - if ( !mirror_off && section % 2 == 1 ) - position = length - position; - } - - // Fetch the key for the position - mlt_geometry_fetch( geometry, output, position ); -} - - -static mlt_geometry transition_parse_keys( mlt_transition transition, const char *name, const char *store, int normalised_width, int normalised_height ) -{ - // Get the properties of the transition - mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); - - // Try to fetch it first - mlt_geometry geometry = mlt_properties_get_data( properties, store, NULL ); - - // Determine length and obtain cycle - mlt_position length = mlt_transition_get_length( transition ); - double cycle = mlt_properties_get_double( properties, "cycle" ); - - // Allow a geometry repeat cycle - if ( cycle >= 1 ) - length = cycle; - else if ( cycle > 0 ) - length *= cycle; - - if ( geometry == NULL ) - { - // Get the new style geometry string - char *property = mlt_properties_get( properties, name ); - - // Create an empty geometries object - geometry = mlt_geometry_init( ); - - // Parse the geometry if we have one - mlt_geometry_parse( geometry, property, length, normalised_width, normalised_height ); - - // Store it - mlt_properties_set_data( properties, store, geometry, 0, ( mlt_destructor )mlt_geometry_close, NULL ); - } - else - { - // Check for updates and refresh if necessary - mlt_geometry_refresh( geometry, mlt_properties_get( properties, name ), length, normalised_width, normalised_height ); - } - - return geometry; -} - -static mlt_geometry composite_calculate( mlt_transition transition, struct mlt_geometry_item_s *result, int nw, int nh, double position ) -{ - // Structures for geometry - mlt_geometry start = transition_parse_keys( transition, "geometry", "geometries", nw, nh ); - - // Do the calculation - geometry_calculate( transition, "geometries", result, position ); - - return start; -} - typedef struct { double matrix[3][3]; @@ -447,7 +370,7 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f // Image, format, width, height and image for the b frame uint8_t *b_image = NULL; - mlt_image_format b_format = mlt_image_rgb24a; + mlt_image_format b_format = mlt_image_rgba; int b_width = mlt_properties_get_int( b_props, "meta.media.width" ); int b_height = mlt_properties_get_int( b_props, "meta.media.height" ); double b_ar = mlt_frame_get_aspect_ratio( b_frame ); @@ -485,7 +408,7 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f } // Fetch the a frame image - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; int error = mlt_frame_get_image( a_frame, image, format, width, height, 1 ); if (error || !image) return error; @@ -497,18 +420,7 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f mlt_service_lock( MLT_TRANSITION_SERVICE( transition ) ); - if (mlt_properties_get(properties, "geometry")) - { - // Structures for geometry - struct mlt_geometry_item_s geometry; - composite_calculate( transition, &geometry, normalised_width, normalised_height, ( double )position ); - result.x = geometry.x; - result.y = geometry.y; - result.w = geometry.w; - result.h = geometry.h; - result.o = geometry.mix / 100.0f; - } - else if (mlt_properties_get(properties, "rect")) + if (mlt_properties_get(properties, "rect")) { // Determine length and obtain cycle double cycle = mlt_properties_get_double( properties, "cycle" ); @@ -621,7 +533,7 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f } // Check that both images are of the correct format and process - if ( *format == mlt_image_rgb24a && b_format == mlt_image_rgb24a ) + if ( *format == mlt_image_rgba && b_format == mlt_image_rgba ) { double sw, sh; // Get values from the transition diff --git a/src/modules/plus/transition_affine.yml b/src/modules/plus/transition_affine.yml index aa3d2ecf5..2cf4109f6 100644 --- a/src/modules/plus/transition_affine.yml +++ b/src/modules/plus/transition_affine.yml @@ -1,8 +1,8 @@ -schema_version: 0.2 +schema_version: 7.0 type: transition identifier: affine title: Transform -version: 5 +version: 6 copyright: Meltytech, LLC creator: Charles Yates contributor: @@ -12,16 +12,11 @@ language: en tags: - Video parameters: - - identifier: geometry - title: Rectangle - type: geometry - description: This property is deprecated. Use rect instead. - - identifier: distort title: Ignore aspect ratio description: > Determines whether the image aspect ratio will be distorted while scaling - to completely fill the geometry rectangle. + to completely fill the rectangle. type: boolean default: 0 mutable: yes @@ -72,10 +67,7 @@ parameters: - identifier: keyed title: Key-framed - description: > - Whether rotate, shear, and offset are key-framed or not. - This ("key-framed") refers to the legacy, deprecated, mlt_geometry-based - property evaluation. Most of the properties support mlt_animation now. + description: Whether rotate, shear, and offset are key-framed or not. type: boolean default: 0 mutable: yes @@ -217,7 +209,7 @@ parameters: - identifier: scale title: Scale description: > - Whether to automatic upscale B frame image to ensure the geometry area + Whether to automatic upscale B frame image to ensure the rectangle is filled. type: boolean default: 0 @@ -261,12 +253,12 @@ parameters: mutable: yes - identifier: fill - title: Fill geometry + title: Fill rectangle description: > - Determines whether the image will be scaled up to fill the geometry. - Otherwise, if the B frame image fits within the geometry, it will not - be scaled. If 0, and the B frame image exceeds the geometry, then it is - scaled down to fit within the geometry. + Determines whether the image will be scaled up to fill the rectangle. + Otherwise, if the B frame image fits within the rectangle, it will not + be scaled. If 0, and the B frame image exceeds the rectangle, then it is + scaled down to fit within the rectangle. type: boolean default: 1 mutable: yes @@ -275,7 +267,7 @@ parameters: - identifier: halign title: Horizontal alignment description: > - Set the horizontal alignment within the geometry rectangle. + Set the horizontal alignment within the rectangle. type: string default: left values: @@ -288,7 +280,7 @@ parameters: - identifier: valign title: Vertical alignment description: > - Set the vertical alignment within the geometry rectangle. + Set the vertical alignment within the rectangle. type: string default: top values: @@ -309,10 +301,9 @@ parameters: - identifier: rect title: Rectangle description: > - This replaces the geometry property and specifies a specifies a rectangle - for the size and position of the image. The format of this is + This specifies the size and position of the image. The format of this is "X/Y:WxH[:opacity]" and can be animated with key frames. - Unlike the geometry property, if you use percentages you must use them for + If you use percentages you must use them for every field in the above format. For example, you cannot mix and match usage of absolute coordinates and percentages for size and opacity. type: rect diff --git a/src/modules/plusgpl/CMakeLists.txt b/src/modules/plusgpl/CMakeLists.txt index cb8c5887f..d5f63e044 100644 --- a/src/modules/plusgpl/CMakeLists.txt +++ b/src/modules/plusgpl/CMakeLists.txt @@ -10,23 +10,24 @@ add_library(mltplusgpl MODULE utils.c ) -target_link_libraries(mltplusgpl mlt m Threads::Threads) +target_compile_options(mltplusgpl PRIVATE ${MLT_COMPILE_OPTIONS}) + +target_link_libraries(mltplusgpl PRIVATE mlt m Threads::Threads) if(WIN32) - target_link_libraries(mltplusgpl ws2_32) -elseif(UNIX) - target_link_libraries(mltplusgpl rt) + target_link_libraries(mltplusgpl PRIVATE ws2_32) +elseif(UNIX AND NOT APPLE) + target_link_libraries(mltplusgpl PRIVATE rt) endif() -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltplusgpl PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +set_target_properties(mltplusgpl PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(TARGETS mltplusgpl LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +install(TARGETS mltplusgpl LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES consumer_cbrts.yml filter_burningtv.yml filter_lumaliftgaingamma.yml filter_rotoscoping.yml - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/plusgpl + DESTINATION ${MLT_INSTALL_DATA_DIR}/plusgpl ) diff --git a/src/modules/plusgpl/consumer_cbrts.c b/src/modules/plusgpl/consumer_cbrts.c index 1e0e95281..9a9a64d20 100644 --- a/src/modules/plusgpl/consumer_cbrts.c +++ b/src/modules/plusgpl/consumer_cbrts.c @@ -132,8 +132,14 @@ typedef struct { uint8_t data[4096]; } ts_section; +typedef struct { + uint8_t *data; + size_t size; +} buffer_t; + static uint8_t null_packet[ TSP_BYTES ]; + /** Forward references to static functions. */ @@ -142,7 +148,7 @@ static int consumer_stop( mlt_consumer parent ); static int consumer_is_stopped( mlt_consumer parent ); static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); -static void on_data_received( mlt_properties properties, mlt_consumer consumer, uint8_t *buf, int size ); +static void on_data_received(mlt_properties properties, mlt_consumer consumer, mlt_event_data ); mlt_consumer consumer_cbrts_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { @@ -993,8 +999,11 @@ static void filter_remux_or_write_packet( consumer_cbrts self, uint8_t *packet ) } } -static void on_data_received( mlt_properties properties, mlt_consumer consumer, uint8_t *buf, int size ) +static void on_data_received( mlt_properties properties, mlt_consumer consumer, mlt_event_data event_data ) { + buffer_t *buffer = mlt_event_data_to_object(event_data); + uint8_t *buf = buffer->data; + size_t size = buffer->size; if ( size > 0 ) { consumer_cbrts self = (consumer_cbrts) consumer->child; diff --git a/src/modules/plusgpl/factory.c b/src/modules/plusgpl/factory.c index d6a5efbed..aa2fbc82c 100644 --- a/src/modules/plusgpl/factory.c +++ b/src/modules/plusgpl/factory.c @@ -36,16 +36,16 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( consumer_type, "cbrts", consumer_cbrts_init ); - MLT_REGISTER( filter_type, "BurningTV", filter_burn_init ); - MLT_REGISTER( filter_type, "burningtv", filter_burn_init ); - MLT_REGISTER( filter_type, "lumaliftgaingamma", filter_lumaliftgaingamma_init ); - MLT_REGISTER( filter_type, "rotoscoping", filter_rotoscoping_init ); - MLT_REGISTER( filter_type, "telecide", filter_telecide_init ); + MLT_REGISTER( mlt_service_consumer_type, "cbrts", consumer_cbrts_init ); + MLT_REGISTER( mlt_service_filter_type, "BurningTV", filter_burn_init ); + MLT_REGISTER( mlt_service_filter_type, "burningtv", filter_burn_init ); + MLT_REGISTER( mlt_service_filter_type, "lumaliftgaingamma", filter_lumaliftgaingamma_init ); + MLT_REGISTER( mlt_service_filter_type, "rotoscoping", filter_rotoscoping_init ); + MLT_REGISTER( mlt_service_filter_type, "telecide", filter_telecide_init ); - MLT_REGISTER_METADATA( consumer_type, "cbrts", metadata, "consumer_cbrts.yml" ); - MLT_REGISTER_METADATA( filter_type, "BurningTV", metadata, "filter_burningtv.yml" ); - MLT_REGISTER_METADATA( filter_type, "burningtv", metadata, "filter_burningtv.yml" ); - MLT_REGISTER_METADATA( filter_type, "lumaliftgaingamma", metadata, "filter_lumaliftgaingamma.yml" ); - MLT_REGISTER_METADATA( filter_type, "rotoscoping", metadata, "filter_rotoscoping.yml" ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "cbrts", metadata, "consumer_cbrts.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "BurningTV", metadata, "filter_burningtv.yml" ); + 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" ); } diff --git a/src/modules/plusgpl/filter_burn.c b/src/modules/plusgpl/filter_burn.c index 6936d6dba..3641b68ce 100644 --- a/src/modules/plusgpl/filter_burn.c +++ b/src/modules/plusgpl/filter_burn.c @@ -79,7 +79,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format mlt_filter filter = mlt_frame_pop_service( frame ); // Get the image - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); // Only process if we have no error and a valid colour space diff --git a/src/modules/plusgpl/filter_lumaliftgaingamma.c b/src/modules/plusgpl/filter_lumaliftgaingamma.c index bc1e9d7ea..0cb00ed85 100644 --- a/src/modules/plusgpl/filter_lumaliftgaingamma.c +++ b/src/modules/plusgpl/filter_lumaliftgaingamma.c @@ -109,7 +109,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); - *format = mlt_image_rgb24; + *format = mlt_image_rgb; int error = mlt_frame_get_image( frame, image, format, width, height, 0 ); // Only process if we have no error and a valid colour space diff --git a/src/modules/plusgpl/filter_rotoscoping.c b/src/modules/plusgpl/filter_rotoscoping.c index 6463449ac..6d493affa 100644 --- a/src/modules/plusgpl/filter_rotoscoping.c +++ b/src/modules/plusgpl/filter_rotoscoping.c @@ -1,6 +1,7 @@ /* * rotoscoping.c -- keyframable vector based rotoscoping * Copyright (C) 2011 Till Theato + * Copyright (C) 2021 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 @@ -64,9 +65,10 @@ static int stringValue( const char *string, const char **stringList, int max ) /** Sets "spline_is_dirty" to 1 if property "spline" was changed. * We then know when to parse the json stored in "spline" */ -static void rotoPropertyChanged( mlt_service owner, mlt_filter this, char *name ) +static void rotoPropertyChanged( mlt_service owner, mlt_filter this, mlt_event_data event_data ) { - if ( !strcmp( name, "spline" ) ) + const char *name = mlt_event_data_to_string(event_data); + if ( name && !strcmp( name, "spline" ) ) mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "_spline_is_dirty", 1 ); } @@ -326,7 +328,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format // Get the image if ( mode == MODE_RGB ) - *format = mlt_image_rgb24; + *format = mlt_image_rgb; int error = mlt_frame_get_image( frame, image, format, width, height, writable ); // Only process if we have no error and a valid colour space @@ -376,7 +378,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format } int bpp; - size = mlt_image_format_size( *format, *width, *height - 1, &bpp ); // mlt_image_format_size increments height! + size = mlt_image_format_size( *format, *width, *height, &bpp ); uint8_t *p = *image; uint8_t *q = *image + size; @@ -386,7 +388,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format switch ( mode ) { case MODE_RGB: - // *format == mlt_image_rgb24 + // *format == mlt_image_rgb while ( p != q ) { if ( !map[i++] ) @@ -397,9 +399,8 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format case MODE_LUMA: switch ( *format ) { - case mlt_image_rgb24: - case mlt_image_rgb24a: - case mlt_image_opengl: + case mlt_image_rgb: + case mlt_image_rgba: while ( p != q ) { p[0] = p[1] = p[2] = map[i++]; @@ -425,8 +426,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format case MODE_ALPHA: switch ( *format ) { - case mlt_image_rgb24a: - case mlt_image_opengl: + case mlt_image_rgba: switch ( mlt_properties_get_int( unique, "alpha_operation" ) ) { case ALPHA_CLEAR: @@ -471,7 +471,13 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format } break; default: - alpha = mlt_frame_get_alpha_mask( frame ); + alpha = mlt_frame_get_alpha( frame ); + if ( !alpha ) + { + alpha = mlt_pool_alloc( length ); + memset( alpha, 255, length ); + mlt_frame_set_alpha( frame, alpha, length, mlt_pool_release ); + } switch ( mlt_properties_get_int( unique, "alpha_operation" ) ) { case ALPHA_CLEAR: diff --git a/src/modules/qt/CMakeLists.txt b/src/modules/qt/CMakeLists.txt index 47eabcfa3..75196a6ad 100644 --- a/src/modules/qt/CMakeLists.txt +++ b/src/modules/qt/CMakeLists.txt @@ -18,7 +18,9 @@ add_library(mltqt MODULE typewriter.cpp ) -target_link_libraries(mltqt +target_compile_options(mltqt PRIVATE ${MLT_COMPILE_OPTIONS}) + +target_link_libraries(mltqt PRIVATE mlt++ mlt m @@ -32,28 +34,31 @@ target_link_libraries(mltqt target_compile_definitions(mltqt PRIVATE USE_QT_OPENGL) +if(NOT WINDOWS_DEPLOY) + target_compile_definitions(mltqt PRIVATE NODEPLOY) +endif() + if(GPL3) target_sources(mltqt PRIVATE transition_vqm.cpp) target_compile_definitions(mltqt PRIVATE GPL3) - install(FILES transition_vqm.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/qt) + install(FILES transition_vqm.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/qt) endif() if(TARGET PkgConfig::FFTW) target_sources(mltqt PRIVATE filter_audiospectrum.cpp filter_lightshow.cpp) - target_link_libraries(mltqt PkgConfig::FFTW) + target_link_libraries(mltqt PRIVATE PkgConfig::FFTW) target_compile_definitions(mltqt PRIVATE USE_FFTW) - install(FILES filter_audiospectrum.yml filter_lightshow.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/qt) + install(FILES filter_audiospectrum.yml filter_lightshow.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/qt) endif() if(TARGET PkgConfig::libexif) - target_link_libraries(mltqt PkgConfig::libexif) + target_link_libraries(mltqt PRIVATE PkgConfig::libexif) target_compile_definitions(mltqt PRIVATE USE_EXIF) endif() -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltqt PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +set_target_properties(mltqt PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(TARGETS mltqt LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +install(TARGETS mltqt LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES filter_audiowaveform.yml @@ -65,5 +70,5 @@ install(FILES producer_qimage.yml producer_qtext.yml transition_qtblend.yml - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/qt + DESTINATION ${MLT_INSTALL_DATA_DIR}/qt ) diff --git a/src/modules/qt/common.cpp b/src/modules/qt/common.cpp index 67bc456de..ec836b646 100644 --- a/src/modules/qt/common.cpp +++ b/src/modules/qt/common.cpp @@ -106,7 +106,7 @@ int create_image( mlt_frame frame, uint8_t **image, mlt_image_format *image_form int error = 0; mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); - *image_format = mlt_image_rgb24a; + *image_format = mlt_image_rgba; // Use the width and height suggested by the rescale filter. if( mlt_properties_get_int( frame_properties, "rescale_width" ) > 0 ) diff --git a/src/modules/qt/consumer_qglsl.cpp b/src/modules/qt/consumer_qglsl.cpp index ca0cf3833..592c2f231 100644 --- a/src/modules/qt/consumer_qglsl.cpp +++ b/src/modules/qt/consumer_qglsl.cpp @@ -1,6 +1,6 @@ /* * consumer_qglsl.cpp - * Copyright (C) 2012-2014 Dan Dennedy + * Copyright (C) 2012-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 @@ -123,19 +123,20 @@ class RenderThread : public QThread QOffscreenSurface* m_surface; }; -static void onThreadCreate(mlt_properties owner, mlt_consumer self, - RenderThread** thread, int* priority, thread_function_t function, void* data ) +static void onThreadCreate(mlt_properties owner, mlt_consumer self, mlt_event_data event_data ) { Q_UNUSED(owner) - Q_UNUSED(priority) - (*thread) = new RenderThread(function, data); - (*thread)->start(); + mlt_event_data_thread* t = (mlt_event_data_thread*) mlt_event_data_to_object(event_data); + auto thread = new RenderThread((thread_function_t) t->function, t->data); + *t->thread = thread; + thread->start(); } -static void onThreadJoin(mlt_properties owner, mlt_consumer self, RenderThread* thread) +static void onThreadJoin(mlt_properties owner, mlt_consumer self, mlt_event_data event_data) { Q_UNUSED(owner) Q_UNUSED(self) + auto thread = (RenderThread*) mlt_event_data_to_object(event_data); if (thread) { thread->quit(); thread->wait(); @@ -160,11 +161,11 @@ static void onThreadStarted(mlt_properties owner, mlt_consumer consumer) #else { #endif - mlt_events_fire(filter_properties, "init glsl", NULL); + mlt_events_fire(filter_properties, "init glsl", mlt_event_data_none()); if (!mlt_properties_get_int(filter_properties, "glsl_supported")) { mlt_log_fatal(service, "OpenGL Shading Language rendering is not supported on this machine.\n" ); - mlt_events_fire(properties, "consumer-fatal-error", NULL); + mlt_events_fire(properties, "consumer-fatal-error", mlt_event_data_none()); } } } @@ -173,7 +174,7 @@ static void onThreadStopped(mlt_properties owner, mlt_consumer consumer) { mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer); mlt_filter filter = (mlt_filter) mlt_properties_get_data(properties, "glslManager", NULL); - mlt_events_fire(MLT_FILTER_PROPERTIES(filter), "close glsl", NULL); + mlt_events_fire(MLT_FILTER_PROPERTIES(filter), "close glsl", mlt_event_data_none()); } static void onCleanup(mlt_properties owner, mlt_consumer consumer) @@ -196,7 +197,7 @@ mlt_consumer consumer_qglsl_init( mlt_profile profile, mlt_service_type type, co if (filter) { mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer); mlt_properties_set_data(properties, "glslManager", filter, 0, (mlt_destructor) mlt_filter_close, NULL); - mlt_events_register( properties, "consumer-cleanup", NULL ); + mlt_events_register( properties, "consumer-cleanup" ); mlt_events_listen(properties, consumer, "consumer-thread-started", (mlt_listener) onThreadStarted); mlt_events_listen(properties, consumer, "consumer-thread-stopped", (mlt_listener) onThreadStopped); mlt_events_listen(properties, consumer, "consumer-cleanup", (mlt_listener) onCleanup); diff --git a/src/modules/qt/factory.c b/src/modules/qt/factory.c index f3f4b61fb..ddb9ef831 100644 --- a/src/modules/qt/factory.c +++ b/src/modules/qt/factory.c @@ -51,36 +51,36 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { #ifdef USE_QT_OPENGL - MLT_REGISTER( consumer_type, "qglsl", consumer_qglsl_init ); + MLT_REGISTER( mlt_service_consumer_type, "qglsl", consumer_qglsl_init ); #endif - MLT_REGISTER( filter_type, "audiowaveform", filter_audiowaveform_init ); - MLT_REGISTER( filter_type, "qtext", filter_qtext_init ); - MLT_REGISTER( producer_type, "qimage", producer_qimage_init ); - MLT_REGISTER( producer_type, "qtext", producer_qtext_init ); - MLT_REGISTER( producer_type, "kdenlivetitle", producer_kdenlivetitle_init ); - MLT_REGISTER( transition_type, "qtblend", transition_qtblend_init ); - MLT_REGISTER( filter_type, "qtblend", filter_qtblend_init ); - MLT_REGISTER( filter_type, "qtcrop", filter_qtcrop_init ); - MLT_REGISTER( filter_type, "typewriter", filter_typewriter_init ); - MLT_REGISTER_METADATA( transition_type, "qtblend", metadata, "transition_qtblend.yml" ); - MLT_REGISTER_METADATA( filter_type, "qtblend", metadata, "filter_qtblend.yml" ); - MLT_REGISTER_METADATA( filter_type, "qtcrop", metadata, "filter_qtcrop.yml" ); + 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 ); + MLT_REGISTER( mlt_service_producer_type, "qtext", producer_qtext_init ); + MLT_REGISTER( mlt_service_producer_type, "kdenlivetitle", producer_kdenlivetitle_init ); + MLT_REGISTER( mlt_service_transition_type, "qtblend", transition_qtblend_init ); + 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_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" ); #ifdef USE_FFTW - MLT_REGISTER( filter_type, "audiospectrum", filter_audiospectrum_init ); - MLT_REGISTER( filter_type, "lightshow", filter_lightshow_init ); + MLT_REGISTER( mlt_service_filter_type, "audiospectrum", filter_audiospectrum_init ); + MLT_REGISTER( mlt_service_filter_type, "lightshow", filter_lightshow_init ); #endif - MLT_REGISTER_METADATA( filter_type, "audiowaveform", metadata, "filter_audiowaveform.yml" ); - MLT_REGISTER_METADATA( filter_type, "qtext", metadata, "filter_qtext.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 - MLT_REGISTER_METADATA( filter_type, "lightshow", metadata, "filter_lightshow.yml" ); - MLT_REGISTER_METADATA( filter_type, "audiospectrum", metadata, "filter_audiospectrum.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "lightshow", metadata, "filter_lightshow.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "audiospectrum", metadata, "filter_audiospectrum.yml" ); #endif - MLT_REGISTER_METADATA( producer_type, "qimage", metadata, "producer_qimage.yml" ); - MLT_REGISTER_METADATA( producer_type, "qtext", metadata, "producer_qtext.yml" ); - MLT_REGISTER_METADATA( producer_type, "kdenlivetitle", metadata, "producer_kdenlivetitle.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "qimage", metadata, "producer_qimage.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "qtext", metadata, "producer_qtext.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "kdenlivetitle", metadata, "producer_kdenlivetitle.yml" ); #ifdef GPL3 - MLT_REGISTER( transition_type, "vqm", transition_vqm_init ); - MLT_REGISTER_METADATA( transition_type, "vqm", metadata, "transition_vqm.yml" ); + MLT_REGISTER( mlt_service_transition_type, "vqm", transition_vqm_init ); + MLT_REGISTER_METADATA( mlt_service_transition_type, "vqm", metadata, "transition_vqm.yml" ); #endif - MLT_REGISTER_METADATA( filter_type, "typewriter", metadata, "filter_typewriter.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "typewriter", metadata, "filter_typewriter.yml" ); } diff --git a/src/modules/qt/filter_audiospectrum.cpp b/src/modules/qt/filter_audiospectrum.cpp index 45fd9ac08..1dc620527 100644 --- a/src/modules/qt/filter_audiospectrum.cpp +++ b/src/modules/qt/filter_audiospectrum.cpp @@ -1,7 +1,6 @@ /* * filter_audiospectrum.cpp -- audio spectrum visualization filter * Copyright (c) 2015-2020 Meltytech, LLC - * Author: Brian Matherly * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -255,7 +254,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format if( mlt_properties_get_data( frame_properties, pdata->fft_prop_name, NULL ) ) { // Get the current image - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; error = mlt_frame_get_image( frame, image, format, width, height, 1 ); // Draw the spectrum diff --git a/src/modules/qt/filter_audiospectrum.yml b/src/modules/qt/filter_audiospectrum.yml index 80d3eb9a5..969447fd5 100644 --- a/src/modules/qt/filter_audiospectrum.yml +++ b/src/modules/qt/filter_audiospectrum.yml @@ -4,7 +4,6 @@ identifier: audiospectrum title: Audio Spectrum Filter version: 1 copyright: Meltytech, LLC -creator: Brian Matherly license: LGPLv2.1 language: en tags: diff --git a/src/modules/qt/filter_audiowaveform.cpp b/src/modules/qt/filter_audiowaveform.cpp index c1d44ac41..0547cbc72 100644 --- a/src/modules/qt/filter_audiowaveform.cpp +++ b/src/modules/qt/filter_audiowaveform.cpp @@ -1,7 +1,6 @@ /* * filter_audiowaveform.cpp -- audio waveform visualization filter - * Copyright (c) 2015-2020 Meltytech, LLC - * Author: Brian Matherly + * 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 @@ -69,9 +68,10 @@ static void destory_save_buffer( void* ptr ) free( buff ); } -static void property_changed( mlt_service owner, mlt_filter filter, char *name ) +static void property_changed( mlt_service owner, mlt_filter filter, mlt_event_data event_data ) { - if ( !strcmp( name, "window" ) ) + const char *name = mlt_event_data_to_string(event_data); + if ( name && !strcmp( name, "window" ) ) { private_data* pdata = (private_data*)filter->child; pdata->reset_window = 1; @@ -340,7 +340,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format if( audio ) { // Get the current image - *image_format = mlt_image_rgb24a; + *image_format = mlt_image_rgba; error = mlt_frame_get_image( frame, image, image_format, width, height, writable ); // Draw the waveforms diff --git a/src/modules/qt/filter_audiowaveform.yml b/src/modules/qt/filter_audiowaveform.yml index 60bd13b13..50896dd5a 100644 --- a/src/modules/qt/filter_audiowaveform.yml +++ b/src/modules/qt/filter_audiowaveform.yml @@ -4,7 +4,6 @@ identifier: audiowaveform title: Audio Waveform Filter version: 1 copyright: Meltytech, LLC -creator: Brian Matherly license: LGPLv2.1 language: en tags: diff --git a/src/modules/qt/filter_lightshow.cpp b/src/modules/qt/filter_lightshow.cpp index ff15ad36b..0e77718ed 100644 --- a/src/modules/qt/filter_lightshow.cpp +++ b/src/modules/qt/filter_lightshow.cpp @@ -208,7 +208,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format mlt_rect rect = mlt_properties_anim_get_rect( filter_properties, "rect", position, length ); // Get the current image - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; error = mlt_frame_get_image( frame, image, format, width, height, 1 ); if ( strchr( mlt_properties_get( filter_properties, "rect" ), '%' ) ) { diff --git a/src/modules/qt/filter_lightshow.yml b/src/modules/qt/filter_lightshow.yml index 66938c4fb..056edf706 100644 --- a/src/modules/qt/filter_lightshow.yml +++ b/src/modules/qt/filter_lightshow.yml @@ -4,7 +4,6 @@ identifier: lightshow title: Light Show version: 1 copyright: Meltytech, LLC -creator: Brian Matherly license: LGPLv2.1 language: en tags: diff --git a/src/modules/qt/filter_qtblend.cpp b/src/modules/qt/filter_qtblend.cpp index 4537c6981..b24cd3c2f 100644 --- a/src/modules/qt/filter_qtblend.cpp +++ b/src/modules/qt/filter_qtblend.cpp @@ -125,7 +125,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format if ( !hasAlpha ) { uint8_t *src_image = NULL; error = mlt_frame_get_image( frame, &src_image, format, &b_width, &b_height, 0 ); - if ( *format == mlt_image_rgb24a || mlt_frame_get_alpha( frame ) ) { + if ( *format == mlt_image_rgba || mlt_frame_get_alpha( frame ) ) { hasAlpha = true; } else { // Prepare output image @@ -137,7 +137,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format } // fetch image - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; uint8_t *src_image = NULL; // Adjust if consumer is scaling diff --git a/src/modules/qt/filter_qtcrop.cpp b/src/modules/qt/filter_qtcrop.cpp index d16b1d71a..43e6e2e22 100644 --- a/src/modules/qt/filter_qtcrop.cpp +++ b/src/modules/qt/filter_qtcrop.cpp @@ -37,11 +37,11 @@ static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format, mlt_rect rect = mlt_properties_anim_get_rect(properties, "rect", position, length); // Get the current image - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; mlt_properties_set_int(MLT_FRAME_PROPERTIES(frame), "resize_alpha", 255); error = mlt_frame_get_image(frame, image, format, width, height, writable); - if (!error && *format == mlt_image_rgb24a) { + if (!error && *format == mlt_image_rgba) { QImage bgImage; convert_mlt_to_qimage_rgba(*image, &bgImage, *width, *height); diff --git a/src/modules/qt/filter_qtext.cpp b/src/modules/qt/filter_qtext.cpp index ea6df2bb1..c9bf3ee2c 100644 --- a/src/modules/qt/filter_qtext.cpp +++ b/src/modules/qt/filter_qtext.cpp @@ -300,7 +300,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format mlt_rect rect = mlt_properties_anim_get_rect( filter_properties, "geometry", position, length ); // Get the current image - *image_format = mlt_image_rgb24a; + *image_format = mlt_image_rgba; mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "resize_alpha", 255 ); mlt_service_lock(MLT_FILTER_SERVICE(filter)); error = mlt_frame_get_image( frame, image, image_format, width, height, writable ); diff --git a/src/modules/qt/filter_qtext.yml b/src/modules/qt/filter_qtext.yml index 007d8a48d..7363cadba 100644 --- a/src/modules/qt/filter_qtext.yml +++ b/src/modules/qt/filter_qtext.yml @@ -4,7 +4,6 @@ identifier: qtext title: QText version: 3 copyright: Meltytech, LLC -creator: Brian Matherly license: LGPLv2.1 language: en tags: diff --git a/src/modules/qt/graph.cpp b/src/modules/qt/graph.cpp index ac2c8a99b..b9200bbf2 100644 --- a/src/modules/qt/graph.cpp +++ b/src/modules/qt/graph.cpp @@ -1,6 +1,5 @@ /* * Copyright (c) 2015-2020 Meltytech, LLC - * Author: Brian Matherly * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/modules/qt/graph.h b/src/modules/qt/graph.h index 695c3edab..69b53f1ea 100644 --- a/src/modules/qt/graph.h +++ b/src/modules/qt/graph.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2015-2020 Meltytech, LLC - * Author: Brian Matherly * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/modules/qt/kdenlivetitle_wrapper.cpp b/src/modules/qt/kdenlivetitle_wrapper.cpp index c6c1b71b2..742685e27 100755 --- a/src/modules/qt/kdenlivetitle_wrapper.cpp +++ b/src/modules/qt/kdenlivetitle_wrapper.cpp @@ -821,7 +821,7 @@ void drawKdenliveTitle( producer_ktitle self, mlt_frame frame, mlt_image_format } } p1.end(); - self->format = mlt_image_rgb24a; + self->format = mlt_image_rgba; convert_qimage_to_mlt_rgba(&img, self->rgba_image, width, height); self->current_image = (uint8_t *) mlt_pool_alloc( image_size ); @@ -841,15 +841,15 @@ void drawKdenliveTitle( producer_ktitle self, mlt_frame frame, mlt_image_format } // Convert image to requested format - if ( format != mlt_image_none && format != mlt_image_glsl && format != self->format ) + if ( format != mlt_image_none && format != mlt_image_movit && format != self->format ) { uint8_t *buffer = NULL; - if ( self->format != mlt_image_rgb24a ) { + if ( self->format != mlt_image_rgba ) { // Image buffer was previously converted, revert to original rgba buffer self->current_image = (uint8_t *) mlt_pool_alloc( image_size ); memcpy(self->current_image, self->rgba_image, image_size); mlt_properties_set_data( producer_props, "_cached_image", self->current_image, image_size, mlt_pool_release, NULL ); - self->format = mlt_image_rgb24a; + self->format = mlt_image_rgba; } // First, set the image so it can be converted when we get it diff --git a/src/modules/qt/producer_kdenlivetitle.c b/src/modules/qt/producer_kdenlivetitle.c index 4dc5d9c6b..352d26b3d 100644 --- a/src/modules/qt/producer_kdenlivetitle.c +++ b/src/modules/qt/producer_kdenlivetitle.c @@ -98,10 +98,8 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form // Clone the image and the alpha int image_size = mlt_image_format_size( self->format, self->current_width, self->current_height, NULL ); uint8_t *image_copy = mlt_pool_alloc( image_size ); - // We use height-1 because mlt_image_format_size() uses height + 1. - // XXX Remove -1 when mlt_image_format_size() is changed. memcpy( image_copy, self->current_image, - mlt_image_format_size( self->format, self->current_width, self->current_height - 1, NULL ) ); + mlt_image_format_size( self->format, self->current_width, self->current_height, NULL ) ); // Now update properties so we free the copy after mlt_frame_set_image( frame, image_copy, image_size, mlt_pool_release ); // We're going to pass the copy on diff --git a/src/modules/qt/producer_qimage.c b/src/modules/qt/producer_qimage.c index 6ddd5c693..728491aba 100644 --- a/src/modules/qt/producer_qimage.c +++ b/src/modules/qt/producer_qimage.c @@ -1,8 +1,6 @@ /* * producer_image.c -- a QT/QImage based producer for MLT - * - * NB: This module is designed to be functionally equivalent to the - * gtk2 image loading module so it can be used as replacement. + * Copyright (C) 2006-2021 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 @@ -48,9 +46,10 @@ static void refresh_length( mlt_properties properties, producer_qimage self ) } } -static void on_property_changed( mlt_service owner, mlt_producer producer, char *name ) +static void on_property_changed( mlt_service owner, mlt_producer producer, mlt_event_data event_data ) { - if ( !strcmp( name, "ttl" ) ) + const char *name = mlt_event_data_to_string(event_data); + if ( name && !strcmp( name, "ttl" ) ) refresh_length( MLT_PRODUCER_PROPERTIES(producer), producer->child ); } diff --git a/src/modules/qt/producer_qtext.cpp b/src/modules/qt/producer_qtext.cpp index ff95a8e26..3a46975cf 100644 --- a/src/modules/qt/producer_qtext.cpp +++ b/src/modules/qt/producer_qtext.cpp @@ -1,7 +1,6 @@ /* * producer_qtext.c -- text generating producer - * Copyright (C) 2013 Brian Matherly - * Author: Brian Matherly + * Copyright (C) 2013 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -332,7 +331,7 @@ static int producer_get_image( mlt_frame frame, uint8_t** buffer, mlt_image_form generate_qimage( frame_properties ); } - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; *width = qImg->width(); *height = qImg->height(); diff --git a/src/modules/qt/producer_qtext.yml b/src/modules/qt/producer_qtext.yml index 76d1b7830..97d5486ef 100644 --- a/src/modules/qt/producer_qtext.yml +++ b/src/modules/qt/producer_qtext.yml @@ -3,8 +3,7 @@ type: producer identifier: qtext title: Qt Titler version: 1 -copyright: Brian Matherly -creator: Brian Matherly +copyright: Meltytech, LLC license: LGPLv2.1 language: en tags: diff --git a/src/modules/qt/qimage_wrapper.cpp b/src/modules/qt/qimage_wrapper.cpp index e022314f3..e0277ff0a 100644 --- a/src/modules/qt/qimage_wrapper.cpp +++ b/src/modules/qt/qimage_wrapper.cpp @@ -1,8 +1,6 @@ /* * qimage_wrapper.cpp -- a QT/QImage based producer for MLT - * - * NB: This module is designed to be functionally equivalent to the - * gtk2 image loading module so it can be used as replacement. + * Copyright (C) 2006-2021 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 @@ -245,7 +243,7 @@ void refresh_image( producer_qimage self, mlt_frame frame, mlt_image_format form self->current_image = NULL; // If we have a qimage and need a new scaled image - if ( self->qimage && ( !self->current_image || ( format != mlt_image_none && format != mlt_image_glsl && format != self->format ) ) ) + 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" ); bool interp = ( interps != "nearest" ) && ( interps != "none" ); @@ -282,7 +280,7 @@ void refresh_image( producer_qimage self, mlt_frame frame, mlt_image_format form #if QT_VERSION >= 0x050200 if ( has_alpha ) { - self->format = mlt_image_rgb24a; + self->format = mlt_image_rgba; scaled = scaled.convertToFormat( QImage::Format_RGBA8888 ); image_size = mlt_image_format_size(self->format, width, height, NULL); self->current_image = ( uint8_t * )mlt_pool_alloc( image_size ); @@ -290,7 +288,7 @@ void refresh_image( producer_qimage self, mlt_frame frame, mlt_image_format form } else { - self->format = mlt_image_rgb24; + self->format = mlt_image_rgb; scaled = scaled.convertToFormat( QImage::Format_RGB888 ); image_size = mlt_image_format_size(self->format, width, height, NULL); self->current_image = ( uint8_t * )mlt_pool_alloc( image_size ); @@ -300,7 +298,7 @@ void refresh_image( producer_qimage self, mlt_frame frame, mlt_image_format form } } #else - self->format = has_alpha? mlt_image_rgb24a : mlt_image_rgb24; + self->format = has_alpha? mlt_image_rgba : mlt_image_rgb; image_size = mlt_image_format_size( self->format, self->current_width, self->current_height, NULL ); self->current_image = ( uint8_t * )mlt_pool_alloc( image_size ); int y = self->current_height + 1; @@ -336,7 +334,7 @@ void refresh_image( producer_qimage self, mlt_frame frame, mlt_image_format form #endif // Convert image to requested format - if ( format != mlt_image_none && format != mlt_image_glsl && format != self->format && enable_caching ) + if ( format != mlt_image_none && format != mlt_image_movit && format != self->format && enable_caching ) { uint8_t *buffer = NULL; diff --git a/src/modules/qt/qimage_wrapper.h b/src/modules/qt/qimage_wrapper.h index dbc6dfe58..d15fdee56 100644 --- a/src/modules/qt/qimage_wrapper.h +++ b/src/modules/qt/qimage_wrapper.h @@ -1,8 +1,6 @@ /* * qimage_wrapper.h -- a QT/QImage based producer for MLT - * - * NB: This module is designed to be functionally equivalent to the - * gtk2 image loading module so it can be used as replacement. + * Copyright (C) 2006-2021 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 diff --git a/src/modules/qt/transition_qtblend.cpp b/src/modules/qt/transition_qtblend.cpp index 09283b012..f5f7d47f1 100644 --- a/src/modules/qt/transition_qtblend.cpp +++ b/src/modules/qt/transition_qtblend.cpp @@ -187,7 +187,7 @@ static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *form { // fetch image error = mlt_frame_get_image( b_frame, &b_image, format, width, height, 1 ); - if ( *format == mlt_image_rgb24a || mlt_frame_get_alpha( b_frame ) ) + if ( *format == mlt_image_rgba || mlt_frame_get_alpha( b_frame ) ) { hasAlpha = true; } @@ -201,7 +201,7 @@ static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *form return 0; } // Get RGBA image to process - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; error = mlt_frame_get_image( b_frame, &b_image, format, &b_width, &b_height, writable ); // Get bottom frame diff --git a/src/modules/qt/transition_vqm.cpp b/src/modules/qt/transition_vqm.cpp index 1fb7db4b0..0dba067f7 100644 --- a/src/modules/qt/transition_vqm.cpp +++ b/src/modules/qt/transition_vqm.cpp @@ -139,7 +139,7 @@ static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *form return 0; // get RGBA image for Qt drawing - *format = mlt_image_rgb24a; + *format = mlt_image_rgba; mlt_frame_get_image( a_frame, image, format, width, height, 1 ); // convert mlt image to qimage diff --git a/src/modules/resample/CMakeLists.txt b/src/modules/resample/CMakeLists.txt index 997cfbbe3..3a7d7570f 100644 --- a/src/modules/resample/CMakeLists.txt +++ b/src/modules/resample/CMakeLists.txt @@ -1,9 +1,11 @@ add_library(mltresample MODULE factory.c filter_resample.c) -target_link_libraries(mltresample mlt PkgConfig::samplerate) -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltresample PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +target_compile_options(mltresample PRIVATE ${MLT_COMPILE_OPTIONS}) -install(TARGETS mltresample LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +target_link_libraries(mltresample PRIVATE mlt PkgConfig::samplerate) -install(FILES filter_resample.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/resample) +set_target_properties(mltresample PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") + +install(TARGETS mltresample LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) + +install(FILES filter_resample.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/resample) diff --git a/src/modules/resample/factory.c b/src/modules/resample/factory.c index da91a3e96..1499058d2 100644 --- a/src/modules/resample/factory.c +++ b/src/modules/resample/factory.c @@ -32,7 +32,7 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( filter_type, "resample", filter_resample_init ); + MLT_REGISTER( mlt_service_filter_type, "resample", filter_resample_init ); - MLT_REGISTER_METADATA( filter_type, "resample", metadata, "filter_resample.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "resample", metadata, "filter_resample.yml" ); } diff --git a/src/modules/resample/filter_resample.c b/src/modules/resample/filter_resample.c index 8bd7c0c33..5325f35ea 100644 --- a/src/modules/resample/filter_resample.c +++ b/src/modules/resample/filter_resample.c @@ -1,6 +1,6 @@ /* * filter_resample.c -- adjust audio sample frequency - * Copyright (C) 2003-2014 Meltytech, LLC + * Copyright (C) 2003-2021 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 @@ -21,143 +21,239 @@ #include #include +#include + #include #include -#include #include -// BUFFER_LEN is based on a maximum of 96KHz, 5 fps, 8 channels -// TODO: dynamically allocate larger buffer size -#define BUFFER_LEN ((96000/5) * 8 * sizeof(float)) -#define RESAMPLE_TYPE SRC_SINC_FASTEST +#define PROCESS_BUFF_SIZE (10000 * sizeof(float)) + +// Private Types +typedef struct +{ + SRC_STATE* s; + int error; + int channels; + float buff[PROCESS_BUFF_SIZE]; + int leftover_samples; +} private_data; /** Get the audio. */ static int resample_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { - int requested_samples = *samples; - - // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); + private_data* pdata = (private_data*)filter->child; + struct mlt_audio_s in; + struct mlt_audio_s out; + mlt_audio_set_values( &out, NULL, *frequency, *format, *samples, *channels ); - // Get the filter properties - mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); - - // Get the resample information - int output_rate = mlt_properties_get_int( filter_properties, "frequency" ); - - // If no resample frequency is specified, default to requested value - if ( output_rate == 0 ) - output_rate = *frequency; + // Apply user requested rate - else will normalize to consumer requested rate; + if ( mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "frequency" ) ) + { + out.frequency = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "frequency" ); + } // Get the producer's audio int error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); - if ( error ) return error; + if ( error || *format == mlt_audio_none || *frequency <= 0 || out.frequency <= 0 || *channels <= 0 ) + { + // Error situation. Do not attempt to convert. + mlt_log_error( MLT_FILTER_SERVICE(filter), "Invalid Parameters: %dS - %dHz %dC %s -> %dHz %dC %s\n", *samples, *frequency, *channels, mlt_audio_format_name( *format ), out.frequency, out.channels, mlt_audio_format_name( out.format ) ); + return error; + } - // Return now if no work to do - if ( output_rate != *frequency && *frequency > 0 && *channels > 0 ) + if ( *samples == 0 ) { - mlt_log_debug( MLT_FILTER_SERVICE(filter), "channels %d samples %d frequency %d -> %d\n", - *channels, *samples, *frequency, output_rate ); + // Noting to convert. No error message needed. + return error; + } + + if( *frequency == out.frequency && !pdata ) + { + // No frequency change, and there is no stored state. + return error; + } + // *Proceed to convert the sampling frequency* + + // The converter operates on interleaved float. Convert the samples if necessary + if ( *format != mlt_audio_f32le ) + { // Do not convert to float unless we need to change the rate - if ( *format != mlt_audio_f32le ) - frame->convert_audio( frame, buffer, format, mlt_audio_f32le ); + frame->convert_audio( frame, buffer, format, mlt_audio_f32le ); + } + + // Set up audio structures and allocate output buffer + mlt_audio_set_values( &in, *buffer, *frequency, *format, *samples, *channels ); + out.format = in.format; + out.channels = in.channels; + mlt_audio_alloc_data( &out ); + mlt_log_debug( MLT_FILTER_SERVICE(filter), "%dHz -> %dHz\n", in.frequency, out.frequency ); + + mlt_service_lock( MLT_FILTER_SERVICE(filter) ); + + // Create the private data if it does not exist + if ( !pdata ) + { + pdata = (private_data*)calloc( 1, sizeof(private_data) ); + pdata->s = NULL; + pdata->channels = 0; + pdata->leftover_samples = 0; + filter->child = pdata; + } - mlt_service_lock( MLT_FILTER_SERVICE(filter) ); + // Recreate the resampler if necessary + if ( !pdata->s || pdata->channels != in.channels ) + { + mlt_log_debug( MLT_FILTER_SERVICE(filter), "Create resample state %d channels\n", in.channels ); + pdata->s = src_delete( pdata->s ); + pdata->s = src_new( SRC_SINC_BEST_QUALITY, in.channels, &pdata->error ); + pdata->channels = in.channels; + } + + int total_consumed_samples = 0; + int consumed_samples = 0; + int received_samples = 0; + int process_buff_samples = PROCESS_BUFF_SIZE / sizeof(float) / in.channels; + + // First copy samples that are leftover from the previous frame + if ( pdata->leftover_samples ) + { + int samples_to_copy = pdata->leftover_samples; + if ( samples_to_copy > out.samples ) + { + samples_to_copy = out.samples; + } + memcpy( out.data, pdata->buff, samples_to_copy * out.channels * sizeof(float) ); + received_samples += samples_to_copy; + pdata->leftover_samples -= samples_to_copy; + } + + // Process all input samples + while ( total_consumed_samples < in.samples || received_samples < out.samples ) + { + if ( pdata->leftover_samples ) + { + mlt_log_error( MLT_FILTER_SERVICE(filter), "Discard leftover samples %d\n", pdata->leftover_samples ); + pdata->leftover_samples = 0; + } + + if ( consumed_samples >= in.samples ) + { + // Continue to repeat input samples into the resampler until it + // provides the desired number of samples out. + consumed_samples = 0; + mlt_log_debug( MLT_FILTER_SERVICE(filter), "Repeat samples\n"); + } SRC_DATA data; - data.data_in = *buffer; - data.data_out = mlt_properties_get_data( filter_properties, "output_buffer", NULL ); - data.src_ratio = ( float ) output_rate / ( float ) *frequency; - data.input_frames = *samples; - data.output_frames = BUFFER_LEN / sizeof(float) / *channels; data.end_of_input = 0; - - SRC_STATE *state = mlt_properties_get_data( filter_properties, "state", NULL ); - if ( !state || mlt_properties_get_int( filter_properties, "channels" ) != *channels ) + data.src_ratio = (double)out.frequency / (double)in.frequency; + data.data_in = (float*)in.data + (consumed_samples * in.channels); + data.input_frames = in.samples - consumed_samples; + data.data_out = pdata->buff; + data.output_frames = process_buff_samples; + if ( total_consumed_samples >= in.samples ) { - // Recreate the resampler if the number of channels changed - state = src_new( RESAMPLE_TYPE, *channels, &error ); - mlt_properties_set_data( filter_properties, "state", state, 0, (mlt_destructor) src_delete, NULL ); - mlt_properties_set_int( filter_properties, "channels", *channels ); + // All input samples have been read once. + // Limit the output frames to the minimum necessary to fill the output frame. + // Limit the input frames to 1 at a time to minimize the duplicated samples. + // Sometimes one input frame can cause many frames to be output from the resampler. + data.input_frames = 1; + if ( data.output_frames > (out.samples - received_samples) ) + { + data.output_frames = out.samples - received_samples; + } } // Resample the audio - src_set_ratio ( state, ( double ) output_rate / ( double ) *frequency ); - error = src_process( state, &data ); - if ( !error ) + src_set_ratio ( pdata->s, data.src_ratio ); + error = src_process( pdata->s, &data ); + if ( error ) + { + mlt_log_error( MLT_FILTER_SERVICE( filter ), "%s %d,%d,%d\n", src_strerror( error ), in.frequency, in.samples, out.frequency ); + break; + } + + // Copy resampled samples from buff to output + if ( data.output_frames_gen ) { - if (data.output_frames_gen < requested_samples) + float* dst = (float*)out.data + (received_samples * out.channels); + int samples_to_copy = data.output_frames_gen; + if ( samples_to_copy > (out.samples - received_samples) ) { - // Duplicate samples to provide the exact requested number of samples to help maintain lipsync. - int bytes_to_copy = data.output_frames_gen * sizeof(float) * *channels; - int byte_offset = (requested_samples* sizeof(float) * *channels) - bytes_to_copy; - if( data.output_frames_gen + byte_offset < BUFFER_LEN ) - { - memmove ( data.data_out + byte_offset, data.data_out, bytes_to_copy ); - data.output_frames_gen += byte_offset; - } + samples_to_copy = out.samples - received_samples; } - else if (data.output_frames_gen > requested_samples) + int bytes_to_copy = samples_to_copy * out.channels * sizeof(float); + memcpy( dst, pdata->buff, bytes_to_copy ); + if ( samples_to_copy < data.output_frames_gen ) { - // Drop samples to provide the exact requested number of samples. - data.output_frames_gen = requested_samples; + // Move leftover samples to the beginning of buff to use next time + pdata->leftover_samples = data.output_frames_gen - samples_to_copy; + float* src = pdata->buff + (samples_to_copy * out.channels); + memmove ( pdata->buff, src , pdata->leftover_samples * out.channels * sizeof(float) ); } - // Update output variables - *samples = data.output_frames_gen; - *frequency = output_rate; - *buffer = data.data_out; - } - else - { - mlt_log_error( MLT_FILTER_SERVICE( filter ), "%s %d,%d,%d\n", src_strerror( error ), *frequency, *samples, output_rate ); + received_samples += samples_to_copy; } - mlt_service_unlock( MLT_FILTER_SERVICE(filter) ); + consumed_samples += data.input_frames_used; + total_consumed_samples += data.input_frames_used; } + mlt_frame_set_audio( frame, out.data, out.format, 0, out.release_data ); + mlt_audio_get_values( &out, buffer, frequency, format, samples, channels ); + + mlt_service_unlock( MLT_FILTER_SERVICE(filter) ); + return error; } /** Filter processing. */ -static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) +static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { if ( mlt_frame_is_test_audio( frame ) == 0 ) { - mlt_frame_push_audio( frame, this ); + mlt_frame_push_audio( frame, filter ); mlt_frame_push_audio( frame, resample_get_audio ); } return frame; } +static void close_filter( mlt_filter filter ) +{ + private_data* pdata = (private_data*)filter->child; + if ( pdata ) + { + if ( pdata->s ) + { + src_delete( pdata->s ); + } + free( pdata ); + filter->child = NULL; + } +} + /** Constructor for the filter. */ mlt_filter filter_resample_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { - mlt_filter this = mlt_filter_new( ); - if ( this != NULL ) + mlt_filter filter = mlt_filter_new(); + + if( filter ) { - int error; - SRC_STATE *state = src_new( RESAMPLE_TYPE, 2 /* channels */, &error ); - if ( error == 0 ) - { - void *output_buffer = mlt_pool_alloc( BUFFER_LEN ); - this->process = filter_process; - if ( arg != NULL ) - mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "frequency", atoi( arg ) ); - mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "channels", 2 ); - mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "state", state, 0, (mlt_destructor)src_delete, NULL ); - mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "output_buffer", output_buffer, BUFFER_LEN, mlt_pool_release, NULL ); - } - else - { - fprintf( stderr, "filter_resample_init: %s\n", src_strerror( error ) ); - } + filter->process = filter_process; + filter->close = close_filter; + filter->child = NULL; + } + else + { + mlt_log_error( MLT_FILTER_SERVICE(filter), "Failed to initialize\n" ); } - return this; + return filter; } diff --git a/src/modules/rtaudio/CMakeLists.txt b/src/modules/rtaudio/CMakeLists.txt index ee2c85f65..bd0d77a30 100644 --- a/src/modules/rtaudio/CMakeLists.txt +++ b/src/modules/rtaudio/CMakeLists.txt @@ -1,35 +1,38 @@ add_library(mltrtaudio MODULE consumer_rtaudio.cpp) -target_link_libraries(mltrtaudio mlt Threads::Threads) + +target_compile_options(mltrtaudio PRIVATE ${MLT_COMPILE_OPTIONS}) + +target_link_libraries(mltrtaudio PRIVATE mlt Threads::Threads) if(TARGET PkgConfig::rtaudio) - target_link_libraries(mltrtaudio PkgConfig::rtaudio) + target_link_libraries(mltrtaudio PRIVATE PkgConfig::rtaudio) else() target_sources(mltrtaudio PRIVATE RtAudio.cpp) + target_include_directories(mltrtaudio PRIVATE .) if(APPLE) - target_link_libraries(mltrtaudio CoreAudio CoreFoundation) + target_link_libraries(mltrtaudio PRIVATE "-framework CoreAudio" "-framework CoreFoundation") target_compile_definitions(mltrtaudio PRIVATE __MACOSX_CORE__) elseif(WIN32) - target_link_libraries(mltrtaudio ole32 dsound winmm ksuser) + target_link_libraries(mltrtaudio PRIVATE ole32 dsound winmm ksuser) target_compile_definitions(mltrtaudio PRIVATE __WINDOWS_DS__ __WINDOWS_WASAPI__) else() if(TARGET PkgConfig::alsa) - target_link_libraries(mltrtaudio PkgConfig::alsa) + target_link_libraries(mltrtaudio PRIVATE PkgConfig::alsa) target_compile_definitions(mltrtaudio PRIVATE __LINUX_ALSA__) endif() if(TARGET PkgConfig::libpulse-simple) - target_link_libraries(mltrtaudio PkgConfig::libpulse-simple) + target_link_libraries(mltrtaudio PRIVATE PkgConfig::libpulse-simple) target_compile_definitions(mltrtaudio PRIVATE __LINUX_PULSE__) endif() if(NOT (TARGET PkgConfig::alsa OR TARGET PkgConfig::libpulse-simple)) - target_link_libraries(mltrtaudio ossaudio) + target_link_libraries(mltrtaudio PRIVATE ossaudio) target_compile_definitions(mltrtaudio PRIVATE __LINUX_OSS__) endif() endif() endif() -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltrtaudio PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +set_target_properties(mltrtaudio PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(TARGETS mltrtaudio LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +install(TARGETS mltrtaudio LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) -install(FILES consumer_rtaudio.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/rtaudio) +install(FILES consumer_rtaudio.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/rtaudio) diff --git a/src/modules/rtaudio/consumer_rtaudio.cpp b/src/modules/rtaudio/consumer_rtaudio.cpp index fa31b55b0..1cc147c39 100644 --- a/src/modules/rtaudio/consumer_rtaudio.cpp +++ b/src/modules/rtaudio/consumer_rtaudio.cpp @@ -1,6 +1,6 @@ /* * consumer_rtaudio.c -- output through RtAudio audio wrapper - * Copyright (C) 2011-2020 Meltytech, LLC + * 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 @@ -28,7 +28,7 @@ #include #endif -static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer consumer, char *name ); +static void consumer_refresh_cb(mlt_consumer sdl, mlt_consumer consumer, mlt_event_data ); static int rtaudio_callback( void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData ); static void *consumer_thread_proxy( void *arg ); @@ -665,8 +665,9 @@ class RtAudioConsumer { // Get the properties of this consumer mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() ); - if ( running && !mlt_consumer_is_stopped( getConsumer() ) ) - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + if ( running && !mlt_consumer_is_stopped( getConsumer() ) ) { + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); + } return 0; } @@ -760,9 +761,10 @@ class RtAudioConsumer }; -static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer consumer, char *name ) +static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer consumer, mlt_event_data event_data ) { - if ( !strcmp( name, "refresh" ) ) + const char *name = mlt_event_data_to_string(event_data); + if ( name && !strcmp( name, "refresh" ) ) { RtAudioConsumer* rtaudio = (RtAudioConsumer*) consumer->child; pthread_mutex_lock( &rtaudio->refresh_mutex ); @@ -885,8 +887,8 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( consumer_type, "rtaudio", consumer_rtaudio_init ); - MLT_REGISTER_METADATA( consumer_type, "rtaudio", metadata, NULL ); + MLT_REGISTER( mlt_service_consumer_type, "rtaudio", consumer_rtaudio_init ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "rtaudio", metadata, NULL ); } } // extern C diff --git a/src/modules/rubberband/CMakeLists.txt b/src/modules/rubberband/CMakeLists.txt index 25e9c7cf2..93264689d 100644 --- a/src/modules/rubberband/CMakeLists.txt +++ b/src/modules/rubberband/CMakeLists.txt @@ -1,9 +1,11 @@ add_library(mltrubberband MODULE factory.c filter_rbpitch.cpp) -target_link_libraries(mltrubberband mlt PkgConfig::rubberband) -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltrubberband PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +target_compile_options(mltrubberband PRIVATE ${MLT_COMPILE_OPTIONS}) -install(TARGETS mltrubberband LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +target_link_libraries(mltrubberband PRIVATE mlt PkgConfig::rubberband) -install(FILES filter_rbpitch.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/rubberband) +set_target_properties(mltrubberband PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") + +install(TARGETS mltrubberband LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) + +install(FILES filter_rbpitch.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/rubberband) diff --git a/src/modules/rubberband/factory.c b/src/modules/rubberband/factory.c index 8df80d895..508201413 100644 --- a/src/modules/rubberband/factory.c +++ b/src/modules/rubberband/factory.c @@ -32,6 +32,6 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( filter_type, "rbpitch", filter_rbpitch_init ); - MLT_REGISTER_METADATA( filter_type, "rbpitch", metadata, "filter_rbpitch.yml" ); + MLT_REGISTER( mlt_service_filter_type, "rbpitch", filter_rbpitch_init ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "rbpitch", metadata, "filter_rbpitch.yml" ); } diff --git a/src/modules/rubberband/filter_rbpitch.cpp b/src/modules/rubberband/filter_rbpitch.cpp index edac25203..525fb94a7 100644 --- a/src/modules/rubberband/filter_rbpitch.cpp +++ b/src/modules/rubberband/filter_rbpitch.cpp @@ -50,7 +50,6 @@ static int rbpitch_get_audio( mlt_frame frame, void **buffer, mlt_audio_format * return mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); } - int requested_samples = *samples; mlt_properties unique_properties = mlt_frame_get_unique_properties( frame, MLT_FILTER_SERVICE(filter) ); if ( !unique_properties ) { @@ -59,6 +58,8 @@ static int rbpitch_get_audio( mlt_frame frame, void **buffer, mlt_audio_format * } // Get the producer's audio + int requested_frequency = *frequency; + int requested_samples = *samples; *format = mlt_audio_float; int error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); if ( error ) return error; @@ -79,7 +80,15 @@ static int rbpitch_get_audio( mlt_frame frame, void **buffer, mlt_audio_format * // the future. double pitchscale = mlt_properties_get_double( unique_properties, "pitchscale" ); pitchscale = CLAMP( pitchscale, 0.05, 50.0 ); - int rubberband_frequency = CLAMP( *frequency, 10000, 300000 ); + double timeratio = 1.0; + int stretch = mlt_properties_get_int( unique_properties, "stretch" ); + int rubberband_frequency = *frequency; + if( stretch ) + { + rubberband_frequency = requested_frequency; + timeratio = (double)requested_samples / (double)*samples; + } + rubberband_frequency = CLAMP( rubberband_frequency, 10000, 300000 ); // Protect the RubberBandStretcher instance. mlt_service_lock( MLT_FILTER_SERVICE(filter) ); @@ -113,6 +122,7 @@ static int rbpitch_get_audio( mlt_frame frame, void **buffer, mlt_audio_format * s->setPitchOption(RubberBandStretcher::OptionPitchHighConsistency); s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth); } + s->setTimeRatio( timeratio ); // Configure input and output buffers and counters. int consumed_samples = 0; @@ -121,6 +131,11 @@ static int rbpitch_get_audio( mlt_frame frame, void **buffer, mlt_audio_format * struct mlt_audio_s in; struct mlt_audio_s out; mlt_audio_set_values( &in, *buffer, *frequency, *format, *samples, *channels ); + if( stretch ) + { + *frequency = requested_frequency; + *samples = requested_samples; + } mlt_audio_set_values( &out, NULL, *frequency, *format, *samples, *channels ); mlt_audio_alloc_data( &out ); @@ -218,6 +233,7 @@ static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) // Save the pitchscale on the frame to be used in rbpitch_get_audio mlt_properties unique_properties = mlt_frame_unique_properties( frame, MLT_FILTER_SERVICE(filter) ); mlt_properties_set_double( unique_properties, "pitchscale", pitchscale ); + mlt_properties_set_int( unique_properties, "stretch", mlt_properties_get_int( filter_properties, "stretch" ) ); mlt_frame_push_audio( frame, (void*)filter ); mlt_frame_push_audio( frame, (void*)rbpitch_get_audio ); diff --git a/src/modules/rubberband/filter_rbpitch.yml b/src/modules/rubberband/filter_rbpitch.yml index 671c29034..563251477 100644 --- a/src/modules/rubberband/filter_rbpitch.yml +++ b/src/modules/rubberband/filter_rbpitch.yml @@ -4,7 +4,6 @@ identifier: rbpitch title: Rubberband Pitch version: 1 copyright: Meltytech, LLC -creator: Brian Matherly license: GPLv2 language: en tags: @@ -47,6 +46,15 @@ parameters: minimum: 0.1 maximum: 10 + - identifier: stretch + title: Stretch + type: boolean + description: > + Stretch the audio to fill the requested samples. This option will have no + effect if the requested sample size is the same as the received sample + size. + readonly: yes + - identifier: latency title: Latency type: float diff --git a/src/modules/sdl/CMakeLists.txt b/src/modules/sdl/CMakeLists.txt index f8b20e15a..cf8cee39b 100644 --- a/src/modules/sdl/CMakeLists.txt +++ b/src/modules/sdl/CMakeLists.txt @@ -6,24 +6,18 @@ add_library(mltsdl MODULE factory.c ) -target_link_libraries(mltsdl mlt m Threads::Threads PkgConfig::sdl) +target_compile_options(mltsdl PRIVATE ${MLT_COMPILE_OPTIONS}) -if(TARGET PkgConfig::sdl_image) - target_sources(mltsdl PRIVATE producer_sdl_image.c) - target_link_libraries(mltsdl PkgConfig::sdl_image) - target_compile_definitions(mltsdl PRIVATE WITH_SDL_IMAGE) - install(FILES producer_sdl_image.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/sdl) -endif() +target_link_libraries(mltsdl PRIVATE mlt m Threads::Threads PkgConfig::sdl) -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltsdl PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +set_target_properties(mltsdl PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(TARGETS mltsdl LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +install(TARGETS mltsdl LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES consumer_sdl_audio.yml consumer_sdl_preview.yml consumer_sdl_still.yml consumer_sdl.yml - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/sdl + DESTINATION ${MLT_INSTALL_DATA_DIR}/sdl ) diff --git a/src/modules/sdl/Makefile b/src/modules/sdl/Makefile index b789750f1..dd86262b0 100644 --- a/src/modules/sdl/Makefile +++ b/src/modules/sdl/Makefile @@ -34,12 +34,6 @@ CFLAGS += $(shell sdl-config --cflags) LDFLAGS += $(shell sdl-config --libs) endif -ifeq ($(WITH_SDL_IMAGE),1) -OBJS += producer_sdl_image.o -CFLAGS += -DWITH_SDL_IMAGE -LDFLAGS += -lSDL_image -endif - SRCS := $(OBJS:.o=.c) ifeq ($(targetos),Darwin) OBJS += consumer_sdl_osx.o diff --git a/src/modules/sdl/configure b/src/modules/sdl/configure index f1d693d2b..8ac51cd6e 100755 --- a/src/modules/sdl/configure +++ b/src/modules/sdl/configure @@ -6,19 +6,10 @@ if [ "$help" != "1" ]; then echo " - using SDL version $(pkg-config --modversion sdl)" echo "USE_PKG_CONFIG=1" > config.mak echo "HAVE_SDL1=1" >> config.mak - image=`pkg-config --variable=prefix sdl`/include/SDL/SDL_image.h - if [ -f "$image" ]; then - echo " - found SDL_image" - echo "WITH_SDL_IMAGE=1" >> config.mak - fi elif sdl-config --version > /dev/null 2>&1 ; then echo " - using SDL version $(sdl-config --version)" echo "USE_PKG_CONFIG=0" > config.mak echo "HAVE_SDL1=1" >> config.mak - image=`sdl-config --prefix`/include/SDL/SDL_image.h - if [ -f "$image" ]; then - echo "WITH_SDL_IMAGE=1" >> config.mak - fi else echo "- SDL development libs not found: disabling" touch ../disable-sdl diff --git a/src/modules/sdl/consumer_sdl.c b/src/modules/sdl/consumer_sdl.c index dd7610037..fd71201ff 100644 --- a/src/modules/sdl/consumer_sdl.c +++ b/src/modules/sdl/consumer_sdl.c @@ -1,6 +1,6 @@ /* * consumer_sdl.c -- A Simple DirectMedia Layer consumer - * Copyright (C) 2003-2019 Meltytech, LLC + * Copyright (C) 2003-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 @@ -156,7 +156,7 @@ mlt_consumer consumer_sdl_init( mlt_profile profile, mlt_service_type type, cons parent->purge = consumer_purge; // Register specific events - mlt_events_register( self->properties, "consumer-sdl-event", ( mlt_transmitter )consumer_sdl_event ); + mlt_events_register( self->properties, "consumer-sdl-event" ); // Return the consumer produced return parent; @@ -169,12 +169,6 @@ mlt_consumer consumer_sdl_init( mlt_profile profile, mlt_service_type type, cons return NULL; } -static void consumer_sdl_event( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) -{ - if ( listener != NULL ) - listener( owner, self, ( SDL_Event * )args[ 0 ] ); -} - int consumer_start( mlt_consumer parent ) { consumer_sdl self = parent->child; @@ -551,7 +545,7 @@ static int consumer_play_video( consumer_sdl self, mlt_frame frame ) while ( SDL_PollEvent( &event ) ) { - mlt_events_fire( self->properties, "consumer-sdl-event", &event, NULL ); + mlt_events_fire( self->properties, "consumer-sdl-event", mlt_event_data_from_object(&event) ); switch( event.type ) { @@ -682,9 +676,7 @@ static int consumer_play_video( consumer_sdl self, mlt_frame frame ) self->buffer = self->sdl_overlay->pixels[ 0 ]; if ( SDL_LockYUVOverlay( self->sdl_overlay ) >= 0 ) { - // We use height-1 because mlt_image_format_size() uses height + 1. - // XXX Remove -1 when mlt_image_format_size() is changed. - int size = mlt_image_format_size( vfmt, width, height - 1, NULL ); + int size = mlt_image_format_size( vfmt, width, height, NULL ); if ( image != NULL ) memcpy( self->buffer, image, size ); SDL_UnlockYUVOverlay( self->sdl_overlay ); @@ -694,14 +686,14 @@ static int consumer_play_video( consumer_sdl self, mlt_frame frame ) sdl_unlock_display(); mlt_cocoa_autorelease_close( pool ); - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); } else if ( self->running ) { - vfmt = preview_format == mlt_image_none ? mlt_image_rgb24a : preview_format; + vfmt = preview_format == mlt_image_none ? mlt_image_rgba : preview_format; if ( !video_off ) mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 ); - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); } return 0; diff --git a/src/modules/sdl/consumer_sdl_audio.c b/src/modules/sdl/consumer_sdl_audio.c index 350bd4a9b..c847cbdf7 100644 --- a/src/modules/sdl/consumer_sdl_audio.c +++ b/src/modules/sdl/consumer_sdl_audio.c @@ -1,6 +1,6 @@ /* * consumer_sdl_audio.c -- A Simple DirectMedia Layer audio-only consumer - * Copyright (C) 2009-2020 Meltytech, LLC + * Copyright (C) 2009-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 @@ -69,7 +69,7 @@ static int consumer_is_stopped( mlt_consumer parent ); static void consumer_purge( mlt_consumer parent ); static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); -static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer self, char *name ); +static void consumer_refresh_cb(mlt_consumer sdl, mlt_consumer self, mlt_event_data ); /** This is what will be called by the factory - anything can be passed in via the argument, but keep it simple. @@ -144,9 +144,10 @@ mlt_consumer consumer_sdl_audio_init( mlt_profile profile, mlt_service_type type return NULL; } -static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, char *name ) +static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, mlt_event_data event_data ) { - if ( !strcmp( name, "refresh" ) ) + const char *name = mlt_event_data_to_string(event_data); + if ( name && !strcmp( name, "refresh" ) ) { consumer_sdl self = parent->child; pthread_mutex_lock( &self->refresh_mutex ); @@ -420,7 +421,7 @@ static int consumer_play_video( consumer_sdl self, mlt_frame frame ) { // Get the properties of this consumer mlt_properties properties = self->properties; - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); return 0; } diff --git a/src/modules/sdl/consumer_sdl_preview.c b/src/modules/sdl/consumer_sdl_preview.c index 0f41c6a0d..1ce26424f 100644 --- a/src/modules/sdl/consumer_sdl_preview.c +++ b/src/modules/sdl/consumer_sdl_preview.c @@ -1,6 +1,6 @@ /* * consumer_sdl_preview.c -- A Simple DirectMedia Layer consumer - * Copyright (C) 2004-2014 Meltytech, LLC + * Copyright (C) 2004-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 @@ -61,9 +61,9 @@ static int consumer_is_stopped( mlt_consumer parent ); static void consumer_purge( mlt_consumer parent ); static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); -static void consumer_frame_show_cb( mlt_consumer sdl, mlt_consumer self, mlt_frame frame ); -static void consumer_sdl_event_cb( mlt_consumer sdl, mlt_consumer self, SDL_Event *event ); -static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer self, char *name ); +static void consumer_frame_show_cb( mlt_consumer sdl, mlt_consumer self, mlt_event_data ); +static void consumer_sdl_event_cb( mlt_consumer sdl, mlt_consumer self, mlt_event_data ); +static void consumer_refresh_cb(mlt_consumer sdl, mlt_consumer self, mlt_event_data ); mlt_consumer consumer_sdl_preview_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { @@ -108,29 +108,33 @@ mlt_consumer consumer_sdl_preview_init( mlt_profile profile, mlt_service_type ty pthread_cond_init( &self->refresh_cond, NULL ); pthread_mutex_init( &self->refresh_mutex, NULL ); mlt_events_listen( MLT_CONSUMER_PROPERTIES( parent ), self, "property-changed", ( mlt_listener )consumer_refresh_cb ); - mlt_events_register( properties, "consumer-sdl-paused", NULL ); + mlt_events_register( properties, "consumer-sdl-paused" ); return parent; } free( self ); return NULL; } -void consumer_frame_show_cb( mlt_consumer sdl, mlt_consumer parent, mlt_frame frame ) +void consumer_frame_show_cb(mlt_consumer sdl, mlt_consumer parent, mlt_event_data event_data ) { + mlt_frame frame = mlt_event_data_to_frame(event_data); consumer_sdl self = parent->child; - self->last_speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ); - self->last_position = mlt_frame_get_position( frame ); - mlt_events_fire( MLT_CONSUMER_PROPERTIES( parent ), "consumer-frame-show", frame, NULL ); + if (frame && self) { + self->last_speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ); + self->last_position = mlt_frame_get_position( frame ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES( parent ), "consumer-frame-show", event_data ); + } } -static void consumer_sdl_event_cb( mlt_consumer sdl, mlt_consumer parent, SDL_Event *event ) +static void consumer_sdl_event_cb( mlt_consumer sdl, mlt_consumer parent, mlt_event_data event_data ) { - mlt_events_fire( MLT_CONSUMER_PROPERTIES( parent ), "consumer-sdl-event", event, NULL ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES( parent ), "consumer-sdl-event", event_data ); } -static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, char *name ) +static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, mlt_event_data event_data ) { - if ( !strcmp( name, "refresh" ) ) + const char *name = mlt_event_data_to_string(event_data); + if ( name && !strcmp( name, "refresh" ) ) { consumer_sdl self = parent->child; pthread_mutex_lock( &self->refresh_mutex ); @@ -421,7 +425,7 @@ static void *consumer_thread( void *arg ) } if ( pause && speed == 0.0 ) { - mlt_events_fire( properties, "consumer-sdl-paused", NULL ); + mlt_events_fire( properties, "consumer-sdl-paused", mlt_event_data_none() ); } } // Allow a little grace time before switching consumers on speed changes @@ -462,7 +466,7 @@ static void *consumer_thread( void *arg ) pthread_mutex_lock( &self->refresh_mutex ); if ( self->running && speed == 0 && self->refresh_count <= 0 ) { - mlt_events_fire( properties, "consumer-sdl-paused", NULL ); + mlt_events_fire( properties, "consumer-sdl-paused", mlt_event_data_none() ); pthread_cond_wait( &self->refresh_cond, &self->refresh_mutex ); } self->refresh_count --; diff --git a/src/modules/sdl/consumer_sdl_still.c b/src/modules/sdl/consumer_sdl_still.c index cc1fe285c..352392669 100644 --- a/src/modules/sdl/consumer_sdl_still.c +++ b/src/modules/sdl/consumer_sdl_still.c @@ -1,6 +1,6 @@ /* * consumer_sdl_still.c -- A Simple DirectMedia Layer consumer - * Copyright (C) 2003-2019 Meltytech, LLC + * Copyright (C) 2003-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 @@ -123,7 +123,7 @@ mlt_consumer consumer_sdl_still_init( mlt_profile profile, mlt_service_type type parent->is_stopped = consumer_is_stopped; // Register specific events - mlt_events_register( this->properties, "consumer-sdl-event", ( mlt_transmitter )consumer_sdl_event ); + mlt_events_register( this->properties, "consumer-sdl-event" ); // Return the consumer produced return parent; @@ -136,12 +136,6 @@ mlt_consumer consumer_sdl_still_init( mlt_profile profile, mlt_service_type type return NULL; } -static void consumer_sdl_event( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ) -{ - if ( listener != NULL ) - listener( owner, this, ( SDL_Event * )args[ 0 ] ); -} - static int consumer_start( mlt_consumer parent ) { consumer_sdl this = parent->child; @@ -372,7 +366,7 @@ static int consumer_play_video( consumer_sdl this, mlt_frame frame ) // Get the properties of this consumer mlt_properties properties = this->properties; - mlt_image_format vfmt = mlt_image_rgb24a; + mlt_image_format vfmt = mlt_image_rgba; int height = this->height; int width = this->width; uint8_t *image = NULL; @@ -397,7 +391,7 @@ static int consumer_play_video( consumer_sdl this, mlt_frame frame ) while ( SDL_PollEvent( &event ) ) { - mlt_events_fire( this->properties, "consumer-sdl-event", &event, NULL ); + mlt_events_fire( this->properties, "consumer-sdl-event", mlt_event_data_from_object(&event) ); switch( event.type ) { @@ -528,7 +522,7 @@ static int consumer_play_video( consumer_sdl this, mlt_frame frame ) sdl_unlock_display(); mlt_cocoa_autorelease_close( pool ); if ( unlock != NULL ) unlock( ); - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); return 1; } @@ -564,7 +558,7 @@ static void *consumer_thread( void *arg ) } else { - mlt_image_format vfmt = mlt_image_rgb24a; + mlt_image_format vfmt = mlt_image_rgba; int height = this->height; int width = this->width; uint8_t *image = NULL; @@ -576,7 +570,7 @@ static void *consumer_thread( void *arg ) mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "format", vfmt ); - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); } mlt_frame_close( frame ); } diff --git a/src/modules/sdl/factory.c b/src/modules/sdl/factory.c index b27fcfc48..f69416c1a 100644 --- a/src/modules/sdl/factory.c +++ b/src/modules/sdl/factory.c @@ -27,9 +27,6 @@ extern mlt_consumer consumer_sdl_audio_init( mlt_profile profile, mlt_service_ty extern mlt_consumer consumer_sdl_still_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_consumer consumer_sdl_preview_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -#ifdef WITH_SDL_IMAGE -extern mlt_producer producer_sdl_image_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -#endif static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { @@ -40,17 +37,13 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( consumer_type, "sdl", consumer_sdl_init ); - MLT_REGISTER_METADATA( consumer_type, "sdl", metadata, "consumer_sdl.yml" ); - MLT_REGISTER( consumer_type, "sdl_audio", consumer_sdl_audio_init ); - MLT_REGISTER_METADATA( consumer_type, "sdl_audio", metadata, "consumer_sdl_audio.yml" ); + MLT_REGISTER( mlt_service_consumer_type, "sdl", consumer_sdl_init ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "sdl", metadata, "consumer_sdl.yml" ); + MLT_REGISTER( mlt_service_consumer_type, "sdl_audio", consumer_sdl_audio_init ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "sdl_audio", metadata, "consumer_sdl_audio.yml" ); - MLT_REGISTER( consumer_type, "sdl_preview", consumer_sdl_preview_init ); - MLT_REGISTER_METADATA( consumer_type, "sdl_preview", metadata, "consumer_sdl_preview.yml" ); - MLT_REGISTER( consumer_type, "sdl_still", consumer_sdl_still_init ); - MLT_REGISTER_METADATA( consumer_type, "sdl_still", metadata, "consumer_sdl_still.yml" ); -#ifdef WITH_SDL_IMAGE - MLT_REGISTER( producer_type, "sdl_image", producer_sdl_image_init ); - MLT_REGISTER_METADATA( producer_type, "sdl_image", metadata, "consumer_sdl_image.yml" ); -#endif + MLT_REGISTER( mlt_service_consumer_type, "sdl_preview", consumer_sdl_preview_init ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "sdl_preview", metadata, "consumer_sdl_preview.yml" ); + MLT_REGISTER( mlt_service_consumer_type, "sdl_still", consumer_sdl_still_init ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "sdl_still", metadata, "consumer_sdl_still.yml" ); } diff --git a/src/modules/sdl/producer_sdl_image.c b/src/modules/sdl/producer_sdl_image.c deleted file mode 100644 index e889486fc..000000000 --- a/src/modules/sdl/producer_sdl_image.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * producer_sdl_image.c -- Image loader which wraps SDL_image - * Copyright (C) 2005-2014 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 -#include -#include -#include -#include -#include -#include -#include - -#include - -static int producer_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) -{ - mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); - SDL_Surface *surface = mlt_properties_get_data( properties, "surface", NULL ); - SDL_Surface *converted = NULL; - - *width = surface->w; - *height = surface->h; - int image_size = *width * *height * 3; - - if ( surface->format->BitsPerPixel != 32 && surface->format->BitsPerPixel != 24 ) - { - SDL_PixelFormat fmt; - fmt.BitsPerPixel = 24; - fmt.BytesPerPixel = 3; - fmt.Rshift = 16; - fmt.Gshift = 8; - fmt.Bshift = 0; - fmt.Rmask = 0xff << 16; - fmt.Gmask = 0xff << 8; - fmt.Bmask = 0xff; - converted = SDL_ConvertSurface( surface, &fmt, 0 ); - } - - switch( surface->format->BitsPerPixel ) - { - case 32: - *format = mlt_image_rgb24a; - image_size = *width * *height * 4; - *image = mlt_pool_alloc( image_size ); - memcpy( *image, surface->pixels, image_size ); - break; - default: - *format = mlt_image_rgb24; - *image = mlt_pool_alloc( image_size ); - memcpy( *image, surface->pixels, image_size ); - break; - } - - if ( converted ) - SDL_FreeSurface( converted ); - - // Update the frame - mlt_frame_set_image( frame, *image, image_size, mlt_pool_release ); - - return 0; -} - -static int filter_files( const struct dirent *de ) -{ - return de->d_name[ 0 ] != '.'; -} - -static mlt_properties parse_file_names( char *resource ) -{ - mlt_properties properties = mlt_properties_new( ); - - if ( strstr( resource, "/.all." ) != NULL ) - { - char *dir_name = strdup( resource ); - char *extension = strrchr( resource, '.' ); - *( strstr( dir_name, "/.all." ) + 1 ) = '\0'; - char fullname[ 1024 ]; - strcpy( fullname, dir_name ); - struct dirent **de = NULL; - int n = scandir( fullname, &de, filter_files, alphasort ); - int i; - struct stat info; - - for (i = 0; i < n; i++ ) - { - snprintf( fullname, 1023, "%s%s", dir_name, de[i]->d_name ); - if ( strstr( fullname, extension ) && lstat( fullname, &info ) == 0 && - ( S_ISREG( info.st_mode ) || info.st_mode | S_IXUSR ) ) - { - char temp[ 20 ]; - sprintf( temp, "%d", i ); - mlt_properties_set( properties, temp, fullname ); - } - free( de[ i ] ); - } - - free( de ); - free( dir_name ); - } - else - { - mlt_properties_set( properties, "0", resource ); - } - - return properties; -} - -static SDL_Surface *load_image( mlt_producer producer ) -{ - mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); - char *resource = mlt_properties_get( properties, "resource" ); - char *last_resource = mlt_properties_get( properties, "_last_resource" ); - int image_idx = 0; - char *this_resource = NULL; - double ttl = mlt_properties_get_int( properties, "ttl" ); - mlt_position position = mlt_producer_position( producer ); - SDL_Surface *surface = mlt_properties_get_data( properties, "_surface", NULL ); - mlt_properties filenames = mlt_properties_get_data( properties, "_filenames", NULL ); - - if ( filenames == NULL ) - { - filenames = parse_file_names( resource ); - mlt_properties_set_data( properties, "_filenames", filenames, 0, ( mlt_destructor )mlt_properties_close, 0 ); - mlt_properties_set_data( properties, "_surface", surface, 0, ( mlt_destructor )SDL_FreeSurface, 0 ); - } - - if ( mlt_properties_count( filenames ) ) - { - image_idx = ( int )floor( ( double )position / ttl ) % mlt_properties_count( filenames ); - this_resource = mlt_properties_get_value( filenames, image_idx ); - - if ( surface == NULL || last_resource == NULL || strcmp( last_resource, this_resource ) ) - { - surface = IMG_Load( this_resource ); - if ( surface != NULL ) - { - surface->refcount ++; - mlt_properties_set_data( properties, "_surface", surface, 0, ( mlt_destructor )SDL_FreeSurface, 0 ); - mlt_properties_set( properties, "_last_resource", this_resource ); - mlt_properties_set_int( properties, "meta.media.width", surface->w ); - mlt_properties_set_int( properties, "meta.media.height", surface->h ); - } - } - else if ( surface != NULL ) - { - surface->refcount ++; - } - } - - return surface; -} - -static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) -{ - // Generate a frame - *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); - - if ( *frame != NULL ) - { - // Create the surface for the current image - SDL_Surface *surface = load_image( producer ); - - if ( surface != NULL ) - { - // Obtain properties of frame and producer - mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); - - // Obtain properties of producer - mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); - - // Update timecode on the frame we're creating - mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); - - // Set producer-specific frame properties - mlt_properties_set_int( properties, "progressive", 1 ); - mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_props, "aspect_ratio" ) ); - mlt_properties_set_data( properties, "surface", surface, 0, ( mlt_destructor )SDL_FreeSurface, NULL ); - - // Push the get_image method - mlt_frame_push_get_image( *frame, producer_get_image ); - } - } - - // Calculate the next timecode - mlt_producer_prepare_next( producer ); - - return 0; -} - -static void producer_close( mlt_producer producer ) -{ - producer->close = NULL; - mlt_producer_close( producer ); - free( producer ); -} - -mlt_producer producer_sdl_image_init( mlt_profile profile, mlt_service_type type, const char *id, char *file ) -{ - mlt_producer producer = calloc( 1, sizeof( struct mlt_producer_s ) ); - if ( producer != NULL && mlt_producer_init( producer, NULL ) == 0 ) - { - // Get the properties interface - mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); - - // Callback registration - producer->get_frame = producer_get_frame; - producer->close = ( mlt_destructor )producer_close; - - // Set the default properties - mlt_properties_set( properties, "resource", file ); - mlt_properties_set( properties, "_resource", "" ); - mlt_properties_set_double( properties, "aspect_ratio", 1 ); - mlt_properties_set_int( properties, "ttl", 25 ); - mlt_properties_set_int( properties, "progressive", 1 ); - - // Validate the resource - SDL_Surface *surface = NULL; - if ( file && ( surface = load_image( producer ) ) ) - { - SDL_FreeSurface( surface ); - mlt_properties_set_data( properties, "_surface", NULL, 0, NULL, NULL ); - } - else - { - producer_close( producer ); - producer = NULL; - } - return producer; - } - free( producer ); - return NULL; -} - - diff --git a/src/modules/sdl/producer_sdl_image.yml b/src/modules/sdl/producer_sdl_image.yml deleted file mode 100644 index 2e85a3732..000000000 --- a/src/modules/sdl/producer_sdl_image.yml +++ /dev/null @@ -1,12 +0,0 @@ -schema_version: 0.1 -type: producer -identifier: sdl_image -title: SDL Image -version: 1 -copyright: Meltytech, LLC -creator: Charles Yates -license: LGPLv2.1 -language: en -notes: DEPRECATED -tags: - - Video diff --git a/src/modules/sdl2/CMakeLists.txt b/src/modules/sdl2/CMakeLists.txt index 4d1b5bd92..8200dc74d 100644 --- a/src/modules/sdl2/CMakeLists.txt +++ b/src/modules/sdl2/CMakeLists.txt @@ -5,11 +5,12 @@ add_library(mltsdl2 MODULE factory.c ) -target_link_libraries(mltsdl2 mlt m Threads::Threads sdl2) +target_compile_options(mltsdl2 PRIVATE ${MLT_COMPILE_OPTIONS}) -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltsdl2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +target_link_libraries(mltsdl2 PRIVATE mlt m Threads::Threads PkgConfig::sdl2) -install(TARGETS mltsdl2 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +set_target_properties(mltsdl2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(FILES consumer_sdl2_audio.yml consumer_sdl2.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/sdl2) +install(TARGETS mltsdl2 LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) + +install(FILES consumer_sdl2_audio.yml consumer_sdl2.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/sdl2) diff --git a/src/modules/sdl2/common.c b/src/modules/sdl2/common.c index 57311e6b3..67d068434 100644 --- a/src/modules/sdl2/common.c +++ b/src/modules/sdl2/common.c @@ -1,7 +1,6 @@ /* * common.h * Copyright (C) 2018 Meltytech, LLC - * Author: Brian Matherly * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -73,4 +72,4 @@ SDL_AudioDeviceID sdl2_open_audio( const SDL_AudioSpec* desired, SDL_AudioSpec* } return dev; -} \ No newline at end of file +} diff --git a/src/modules/sdl2/common.h b/src/modules/sdl2/common.h index abe86ca99..23e5fbe19 100644 --- a/src/modules/sdl2/common.h +++ b/src/modules/sdl2/common.h @@ -1,7 +1,6 @@ /* * common.h * Copyright (C) 2018 Meltytech, LLC - * Author: Brian Matherly * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/modules/sdl2/consumer_sdl2.c b/src/modules/sdl2/consumer_sdl2.c index 9edc767fd..d31eec999 100644 --- a/src/modules/sdl2/consumer_sdl2.c +++ b/src/modules/sdl2/consumer_sdl2.c @@ -1,6 +1,6 @@ /* * consumer_sdl.c -- A Simple DirectMedia Layer consumer - * Copyright (C) 2017-2019 Meltytech, LLC + * Copyright (C) 2017-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 @@ -84,7 +84,6 @@ static int consumer_is_stopped( mlt_consumer parent ); static void consumer_purge( mlt_consumer parent ); static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); -static void consumer_sdl_event( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ); static int setup_sdl_video( consumer_sdl self ); /** This is what will be called by the factory - anything can be passed in @@ -156,7 +155,7 @@ mlt_consumer consumer_sdl2_init( mlt_profile profile, mlt_service_type type, con parent->purge = consumer_purge; // Register specific events - mlt_events_register( self->properties, "consumer-sdl-event", ( mlt_transmitter )consumer_sdl_event ); + mlt_events_register( self->properties, "consumer-sdl-event" ); // Return the consumer produced return parent; @@ -169,12 +168,6 @@ mlt_consumer consumer_sdl2_init( mlt_profile profile, mlt_service_type type, con return NULL; } -static void consumer_sdl_event( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) -{ - if ( listener != NULL ) - listener( owner, self, ( SDL_Event * )args[ 0 ] ); -} - int consumer_start( mlt_consumer parent ) { consumer_sdl self = parent->child; @@ -525,10 +518,10 @@ static int setup_sdl_video( consumer_sdl self ) int image_format = mlt_properties_get_int( self->properties, "mlt_image_format" ); if ( image_format ) switch ( image_format ) { - case mlt_image_rgb24: + case mlt_image_rgb: texture_format = SDL_PIXELFORMAT_RGB24; break; - case mlt_image_rgb24a: + case mlt_image_rgba: texture_format = SDL_PIXELFORMAT_ABGR8888; break; case mlt_image_yuv420p: @@ -668,9 +661,7 @@ static int consumer_play_video( consumer_sdl self, mlt_frame frame ) unsigned char* planes[4]; int strides[4]; - // We use height-1 because mlt_image_format_size() uses height + 1. - // XXX Remove -1 when mlt_image_format_size() is changed. - mlt_image_format_planes( vfmt, width, height - 1, image, planes, strides ); + mlt_image_format_planes( vfmt, width, height, image, planes, strides ); if ( strides[1] ) { SDL_UpdateYUVTexture( self->sdl_texture, NULL, planes[0], strides[0], @@ -684,16 +675,16 @@ static int consumer_play_video( consumer_sdl self, mlt_frame frame ) SDL_RenderPresent( self->sdl_renderer ); } - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); } else if ( self->running ) { if ( !video_off ) { mlt_image_format preview_format = mlt_properties_get_int( properties, "preview_format" ); - vfmt = preview_format == mlt_image_none ? mlt_image_rgb24a : preview_format; + vfmt = preview_format == mlt_image_none ? mlt_image_rgba : preview_format; mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 ); } - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); } return 0; diff --git a/src/modules/sdl2/consumer_sdl2_audio.c b/src/modules/sdl2/consumer_sdl2_audio.c index e8527d2b8..fc658fd4e 100644 --- a/src/modules/sdl2/consumer_sdl2_audio.c +++ b/src/modules/sdl2/consumer_sdl2_audio.c @@ -1,6 +1,6 @@ /* * consumer_sdl2_audio.c -- A Simple DirectMedia Layer audio-only consumer - * Copyright (C) 2009-2020 Meltytech, LLC + * Copyright (C) 2009-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 @@ -75,7 +75,7 @@ static int consumer_is_stopped( mlt_consumer parent ); static void consumer_purge( mlt_consumer parent ); static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); -static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer self, char *name ); +static void consumer_refresh_cb(mlt_consumer sdl, mlt_consumer self, mlt_event_data ); /** This is what will be called by the factory - anything can be passed in via the argument, but keep it simple. @@ -147,9 +147,10 @@ mlt_consumer consumer_sdl2_audio_init( mlt_profile profile, mlt_service_type typ return NULL; } -static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, char *name ) +static void consumer_refresh_cb( mlt_consumer sdl, mlt_consumer parent, mlt_event_data event_data ) { - if ( !strcmp( name, "refresh" ) ) + const char *name = mlt_event_data_to_string(event_data); + if ( name && !strcmp( name, "refresh" ) ) { consumer_sdl self = parent->child; pthread_mutex_lock( &self->refresh_mutex ); @@ -444,7 +445,7 @@ static int consumer_play_video( consumer_sdl self, mlt_frame frame ) { // Get the properties of this consumer mlt_properties properties = self->properties; - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); return 0; } diff --git a/src/modules/sdl2/factory.c b/src/modules/sdl2/factory.c index d357e68ce..e07a789d7 100644 --- a/src/modules/sdl2/factory.c +++ b/src/modules/sdl2/factory.c @@ -34,8 +34,8 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( consumer_type, "sdl2", consumer_sdl2_init ); - MLT_REGISTER_METADATA( consumer_type, "sdl2", metadata, "consumer_sdl2.yml" ); - MLT_REGISTER( consumer_type, "sdl2_audio", consumer_sdl2_audio_init ); - MLT_REGISTER_METADATA( consumer_type, "sdl2_audio", metadata, "consumer_sdl_audio.yml" ); + 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" ); } diff --git a/src/modules/sox/CMakeLists.txt b/src/modules/sox/CMakeLists.txt index 8377a38e9..6fa3a5ba8 100644 --- a/src/modules/sox/CMakeLists.txt +++ b/src/modules/sox/CMakeLists.txt @@ -1,13 +1,15 @@ add_library(mltsox MODULE factory.c filter_sox.c) -target_link_libraries(mltsox mlt m PkgConfig::sox) + +target_compile_options(mltsox PRIVATE ${MLT_COMPILE_OPTIONS}) + +target_link_libraries(mltsox PRIVATE mlt m PkgConfig::sox) if(${sox_VERSION} GREATER 13) target_compile_definitions(mltsox PRIVATE SOX14) endif() -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltsox PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +set_target_properties(mltsox PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(TARGETS mltsox LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +install(TARGETS mltsox LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) -install(FILES filter_sox_effect.yml filter_sox.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/sox) +install(FILES filter_sox_effect.yml filter_sox.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/sox) diff --git a/src/modules/sox/factory.c b/src/modules/sox/factory.c index 8776ac162..297f362cb 100644 --- a/src/modules/sox/factory.c +++ b/src/modules/sox/factory.c @@ -37,7 +37,7 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat result = mlt_properties_parse_yaml( file ); #ifdef SOX14 - if ( result && ( type == filter_type ) && strcmp( id, "sox" ) ) + if ( result && ( type == mlt_service_filter_type ) && strcmp( id, "sox" ) ) { // Annotate the yaml properties with sox effect usage. mlt_properties params = mlt_properties_get_data( result, "parameters", NULL ); @@ -67,8 +67,8 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( filter_type, "sox", filter_sox_init ); - MLT_REGISTER_METADATA( filter_type, "sox", metadata, NULL ); + MLT_REGISTER( mlt_service_filter_type, "sox", filter_sox_init ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "sox", metadata, NULL ); #ifdef SOX14 int i; const sox_effect_handler_t *e; @@ -83,8 +83,8 @@ MLT_REPOSITORY ) { strcpy( name + 4, e->name ); - MLT_REGISTER( filter_type, name, filter_sox_init ); - MLT_REGISTER_METADATA( filter_type, name, metadata, NULL ); + MLT_REGISTER( mlt_service_filter_type, name, filter_sox_init ); + MLT_REGISTER_METADATA( mlt_service_filter_type, name, metadata, NULL ); } } #endif diff --git a/src/modules/swfdec/Makefile b/src/modules/swfdec/Makefile deleted file mode 100644 index ae18e44d4..000000000 --- a/src/modules/swfdec/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -CFLAGS += -I../.. - -LDFLAGS += -L../../framework -lmlt -lm - -include ../../../config.mak -include config.mak - -TARGET = ../libmltswfdec$(LIBSUF) - -OBJS = producer_swfdec.o - -ifeq ($(targetos), MinGW) -LDFLAGS += -Wl,enable-auto-import -lz -endif - -SRCS := $(OBJS:.o=.c) - -all: $(TARGET) - -$(TARGET): $(OBJS) - $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) - -depend: $(SRCS) - $(CC) -MM $(CFLAGS) $^ 1>.depend - -distclean: clean - rm -f .depend - -clean: - rm -f $(OBJS) $(TARGET) - -install: all - install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" - install -d "$(DESTDIR)$(mltdatadir)/swfdec" - install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/swfdec" - -ifneq ($(wildcard .depend),) -include .depend -endif diff --git a/src/modules/swfdec/configure b/src/modules/swfdec/configure deleted file mode 100755 index cffd6df9e..000000000 --- a/src/modules/swfdec/configure +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh - -if [ "$help" != "1" ] -then - pkg-config swfdec-0.9 2> /dev/null - disable_swfdec=$? - echo > config.mak - if [ "$disable_swfdec" = "0" ] - then - echo "CFLAGS += $(pkg-config --cflags swfdec-0.9)" >> config.mak - echo "LDFLAGS += $(pkg-config --libs swfdec-0.9)" >> config.mak - else - pkg-config swfdec-0.8 2> /dev/null - disable_swfdec=$? - if [ "$disable_swfdec" = "0" ] - then - echo "CFLAGS += $(pkg-config --cflags swfdec-0.8)" >> config.mak - echo "LDFLAGS += $(pkg-config --libs swfdec-0.8)" >> config.mak - else - pkg-config swfdec-0.7 2> /dev/null - disable_swfdec=$? - if [ "$disable_swfdec" = "0" ] - then - echo "CFLAGS += $(pkg-config --cflags swfdec-0.7)" >> config.mak - echo "LDFLAGS += $(pkg-config --libs swfdec-0.7)" >> config.mak - else - echo "- swfdec not found: disabling" - touch ../disable-swfdec - exit 0 - fi - fi - fi -fi diff --git a/src/modules/swfdec/producer_swfdec.c b/src/modules/swfdec/producer_swfdec.c deleted file mode 100644 index da13acf4b..000000000 --- a/src/modules/swfdec/producer_swfdec.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * producer_swfdec.c -- swfdec producer for Flash files - * Copyright (C) 2010 Dan Dennedy - * - * swfdec 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. - * - * swfdec 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 swfdec library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include - -#include -#include -#include -#include -#include - -typedef struct -{ - struct mlt_producer_s parent; - SwfdecPlayer *player; - SwfdecURL *url; - cairo_surface_t *surface; - cairo_t *cairo; - mlt_position last_position; - guint width; - guint height; -} *producer_swfdec; - -void swfdec_open( producer_swfdec swfdec, mlt_profile profile ) -{ - mlt_properties properties = MLT_PRODUCER_PROPERTIES( &swfdec->parent ); - - // Setup the swfdec player - swfdec->player = swfdec_player_new( NULL ); - if ( mlt_properties_get( properties, "variables") ) - swfdec_player_set_variables( swfdec->player, mlt_properties_get( properties, "variables" ) ); - swfdec_player_set_url( swfdec->player, swfdec->url ); - swfdec_player_set_maximum_runtime( swfdec->player, 10000 ); - - // Setup size - swfdec_player_get_default_size( swfdec->player, &swfdec->width, &swfdec->height ); - if ( swfdec->width == 0 || swfdec->height == 0 ) - { - swfdec_player_set_size( swfdec->player, profile->width, profile->height ); - swfdec->width = profile->width; - swfdec->height = profile->height; - } - - // Setup scaling - double scale = 1.0; - if ( swfdec->width > 2 * swfdec->height ) - scale = 0.5 * profile->width / swfdec->height; - else if ( swfdec->height > 2 * swfdec->width ) - scale = 0.5 * profile->height / swfdec->width; - else - scale = (double) profile->width / MAX( swfdec->width, swfdec->height ); - swfdec->width = ceil( scale * swfdec->width ); - swfdec->height = ceil( scale * swfdec->height ); - - // Compute the centering translation - double x = swfdec->width > profile->width ? (swfdec->width - profile->width) / 2 : 0; - double y = swfdec->height > profile->height ? (swfdec->height - profile->height) / 2 : 0; - - // Setup cairo - swfdec->surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, MIN(profile->width, swfdec->width), MIN(profile->height, swfdec->height) ); - swfdec->cairo = cairo_create( swfdec->surface ); - cairo_translate( swfdec->cairo, -x, -y ); - cairo_scale( swfdec->cairo, scale, scale ); -} - -void swfdec_close( producer_swfdec swfdec ) -{ - if ( swfdec->cairo ) - cairo_destroy( swfdec->cairo ); - swfdec->cairo = NULL; - if ( swfdec->player ) - g_object_unref( swfdec->player ); - swfdec->player = NULL; - if ( swfdec->surface ) - cairo_surface_destroy( swfdec->surface ); - swfdec->surface = NULL; -} - -// Cairo uses 32 bit native endian ARGB -static void bgra_to_rgba( uint8_t *src, uint8_t* dst, int width, int height ) -{ - int n = width * height + 1; - - while ( --n ) - { - *dst++ = src[2]; - *dst++ = src[1]; - *dst++ = src[0]; - *dst++ = src[3]; - src += 4; - } -} - -static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) -{ - producer_swfdec swfdec = mlt_frame_pop_service( frame ); - mlt_service service = MLT_PRODUCER_SERVICE( &swfdec->parent ); - mlt_profile profile = mlt_service_profile( service ); - - mlt_service_lock( service ); - - if ( !swfdec->player ) - swfdec_open( swfdec, profile ); - - // Set width and height - *width = swfdec->width; - *height = swfdec->height; - *format = mlt_image_rgb24a; - int size = mlt_image_format_size( *format, *width, *height, NULL ); - - *buffer = mlt_pool_alloc( size ); - mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); - - // Seek - mlt_position pos = mlt_frame_original_position( frame ); - if ( pos > swfdec->last_position ) - { - gulong msec = 1000UL * ( pos - swfdec->last_position ) * profile->frame_rate_den / profile->frame_rate_num; - while ( msec > 0 ) - msec -= swfdec_player_advance( swfdec->player, msec ); - } - else if ( pos < swfdec->last_position ) - { - swfdec_close( swfdec ); - swfdec_open( swfdec, mlt_service_profile( service ) ); - gulong msec = 1000UL * pos * profile->frame_rate_den / profile->frame_rate_num; - while ( msec > 0 ) - msec -= swfdec_player_advance( swfdec->player, msec ); - } - swfdec->last_position = pos; - - // Render - cairo_save( swfdec->cairo ); - //cairo_set_source_rgba( swfdec->cairo, r, g, b, a ); - cairo_set_operator( swfdec->cairo, CAIRO_OPERATOR_CLEAR ); - cairo_paint( swfdec->cairo ); - cairo_restore( swfdec->cairo ); - swfdec_player_render( swfdec->player, swfdec->cairo ); - - // Get image from surface - uint8_t *image = cairo_image_surface_get_data( swfdec->surface ); - - mlt_service_unlock( service ); - - // Convert to RGBA - bgra_to_rgba( image, *buffer, swfdec->width, swfdec->height ); - - return 0; -} - -static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) -{ - // Access the private data - producer_swfdec swfdec = producer->child; - - // Create an empty frame - *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); - - // Get the frames properties - mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); - - // Update other info on the frame - mlt_properties_set_int( properties, "test_image", 0 ); - mlt_properties_set_int( properties, "width", swfdec->width ); - mlt_properties_set_int( properties, "height", swfdec->height ); - mlt_properties_set_int( properties, "progressive", 1 ); - mlt_properties_set_double( properties, "aspect_ratio", 1.0 ); - - // Push the get_image method on to the stack - mlt_frame_push_service( *frame, swfdec ); - mlt_frame_push_get_image( *frame, get_image ); - - // Update timecode on the frame we're creating - mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); - - // Calculate the next timecode - mlt_producer_prepare_next( producer ); - - return 0; -} - -static void producer_close( mlt_producer parent ) -{ - // Obtain swfdec - producer_swfdec swfdec = parent->child; - - // Close the file - swfdec_close( swfdec ); - if ( swfdec->url ) - swfdec_url_free( swfdec->url ); - - // Close the parent - parent->close = NULL; - mlt_producer_close( parent ); - - // Free the memory - free( swfdec ); -} - -mlt_producer producer_swfdec_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename ) -{ - if ( !filename ) return NULL; - producer_swfdec swfdec = calloc( 1, sizeof( *swfdec ) ); - mlt_producer producer = NULL; - - if ( swfdec && mlt_producer_init( &swfdec->parent, swfdec ) == 0 ) - { - // Initialize swfdec and try to open the file - swfdec->url = swfdec_url_new_from_input( filename ); - if ( swfdec->url ) - { - // Set the return value - producer = &swfdec->parent; - - // Set the resource property (required for all producers) - mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); - mlt_properties_set( properties, "resource", filename ); - - // Set the callbacks - producer->close = (mlt_destructor) producer_close; - producer->get_frame = get_frame; - - // Set the meta media attributes - swfdec->width = profile->width; - swfdec->height = profile->height; - mlt_properties_set_int( properties, "meta.media.nb_streams", 1 ); - mlt_properties_set( properties, "meta.media.0.stream.type", "video" ); - mlt_properties_set( properties, "meta.media.0.codec.name", "swf" ); - mlt_properties_set( properties, "meta.media.0.codec.long_name", "Adobe Flash" ); - mlt_properties_set( properties, "meta.media.0.codec.pix_fmt", "bgra" ); - mlt_properties_set_int( properties, "meta.media.width", profile->width ); - mlt_properties_set_int( properties, "meta.media.height", profile->height ); - mlt_properties_set_double( properties, "meta.media.sample_aspect_num", 1.0 ); - mlt_properties_set_double( properties, "meta.media.sample_aspect_den", 1.0 ); - mlt_properties_set_int( properties, "meta.media.frame_rate_num", profile->frame_rate_num ); - mlt_properties_set_int( properties, "meta.media.frame_rate_den", profile->frame_rate_den ); - mlt_properties_set_int( properties, "meta.media.progressive", 1 ); - } - else - { - g_object_unref( swfdec->player ); - mlt_producer_close( &swfdec->parent ); - free( swfdec ); - } - } - else - { - free( swfdec ); - } - - return producer; -} - -static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) -{ - char file[ PATH_MAX ]; - snprintf( file, PATH_MAX, "%s/swfdec/%s", mlt_environment( "MLT_DATA" ), (char*) data ); - return mlt_properties_parse_yaml( file ); -} - -MLT_REPOSITORY -{ - swfdec_init(); - MLT_REGISTER( producer_type, "swfdec", producer_swfdec_init ); - MLT_REGISTER_METADATA( producer_type, "swfdec", metadata, "producer_swfdec.yml" ); -} diff --git a/src/modules/swfdec/producer_swfdec.yml b/src/modules/swfdec/producer_swfdec.yml deleted file mode 100644 index 987aadc43..000000000 --- a/src/modules/swfdec/producer_swfdec.yml +++ /dev/null @@ -1,11 +0,0 @@ -schema_version: 0.1 -type: producer -identifier: swfdec -title: Flash -version: 1 -copyright: Dan Dennedy -creator: Dan Dennedy -license: LGPLv2.1 -language: en -tags: - - Video diff --git a/src/modules/vid.stab/CMakeLists.txt b/src/modules/vid.stab/CMakeLists.txt index f3f2fec8a..434691c61 100644 --- a/src/modules/vid.stab/CMakeLists.txt +++ b/src/modules/vid.stab/CMakeLists.txt @@ -5,11 +5,12 @@ add_library(mltvidstab MODULE filter_vidstab.cpp ) -target_link_libraries(mltvidstab mlt m mlt++ PkgConfig::vidstab) +target_compile_options(mltvidstab PRIVATE ${MLT_COMPILE_OPTIONS}) -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltvidstab PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +target_link_libraries(mltvidstab PRIVATE mlt m mlt++ PkgConfig::vidstab) -install(TARGETS mltvidstab LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +set_target_properties(mltvidstab PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(FILES filter_deshake.yml filter_vidstab.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/vidstab) +install(TARGETS mltvidstab LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) + +install(FILES filter_deshake.yml filter_vidstab.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/vidstab) diff --git a/src/modules/vid.stab/common.c b/src/modules/vid.stab/common.c index 9899f3ed6..3da5df62f 100644 --- a/src/modules/vid.stab/common.c +++ b/src/modules/vid.stab/common.c @@ -1,6 +1,6 @@ /* * common.c - * Copyright (C) 2014 Brian Matherly + * Copyright (C) 2014 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 diff --git a/src/modules/vid.stab/common.h b/src/modules/vid.stab/common.h index ff175c2a5..967698072 100644 --- a/src/modules/vid.stab/common.h +++ b/src/modules/vid.stab/common.h @@ -1,7 +1,7 @@ /* * common.h * Copyright (C) 2013 Jakub Ksiezniak - * Copyright (C) 2014 Brian Matherly + * Copyright (C) 2014 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 diff --git a/src/modules/vid.stab/factory.c b/src/modules/vid.stab/factory.c index 0f54f239f..193aca2f8 100644 --- a/src/modules/vid.stab/factory.c +++ b/src/modules/vid.stab/factory.c @@ -33,9 +33,9 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( filter_type, "deshake", filter_deshake_init ); - MLT_REGISTER( filter_type, "vidstab", filter_vidstab_init ); + MLT_REGISTER( mlt_service_filter_type, "deshake", filter_deshake_init ); + MLT_REGISTER( mlt_service_filter_type, "vidstab", filter_vidstab_init ); - MLT_REGISTER_METADATA( filter_type, "deshake", metadata, "filter_deshake.yml" ); - MLT_REGISTER_METADATA( filter_type, "vidstab", metadata, "filter_vidstab.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "deshake", metadata, "filter_deshake.yml" ); + MLT_REGISTER_METADATA( mlt_service_filter_type, "vidstab", metadata, "filter_vidstab.yml" ); } diff --git a/src/modules/vid.stab/filter_deshake.cpp b/src/modules/vid.stab/filter_deshake.cpp index e9eb0f981..a601ce9aa 100644 --- a/src/modules/vid.stab/filter_deshake.cpp +++ b/src/modules/vid.stab/filter_deshake.cpp @@ -2,7 +2,7 @@ * filter_deshake.cpp * Copyright (C) 2013 Marco Gittler * Copyright (C) 2013 Jakub Ksiezniak - * Copyright (C) 2014 Brian Matherly + * Copyright (C) 2014 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 diff --git a/src/modules/vid.stab/filter_vidstab.cpp b/src/modules/vid.stab/filter_vidstab.cpp index 56704aaf0..b0beee4da 100644 --- a/src/modules/vid.stab/filter_vidstab.cpp +++ b/src/modules/vid.stab/filter_vidstab.cpp @@ -2,7 +2,7 @@ * filter_vidstab.cpp * Copyright (C) 2013 Marco Gittler * Copyright (C) 2013 Jakub Ksiezniak - * Copyright (C) 2014 Brian Matherly + * Copyright (C) 2014 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 diff --git a/src/modules/videostab/Makefile b/src/modules/videostab/Makefile deleted file mode 100644 index c9d6eedfb..000000000 --- a/src/modules/videostab/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -include ../../../config.mak - -CFLAGS += -I../.. -ifdef SSE2_FLAGS -CFLAGS += -msse2 -endif - -LDFLAGS += -L../../framework -lmlt -lm - - -TARGET = ../libmltvideostab$(LIBSUF) - -OBJS = factory.o \ - filter_videostab.o filter_videostab2.o \ - stabilize.o transform.o transform_image.o tlist.o\ - stab/klt/convolve.o stab/klt/klt.o stab/klt/pyramid.o stab/klt/trackFeatures.o \ - stab/klt/error.o stab/klt/klt_util.o stab/klt/selectGoodFeatures.o \ - stab/estimate.o stab/resample.o stab/utils.o stab/vector.o - -SRCS := $(OBJS:.o=.c) - -all: $(TARGET) - -$(TARGET): $(OBJS) - $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) - -depend: $(SRCS) - $(CC) -MM $(CFLAGS) $^ 1>.depend - -distclean: clean - rm -f .depend - -clean: - rm -f $(OBJS) $(TARGET) - -install: all - install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" - install -d $(DESTDIR)$(mltdatadir)/videostab - install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/videostab" - - -ifneq ($(wildcard .depend),) -include .depend -endif diff --git a/src/modules/videostab/factory.c b/src/modules/videostab/factory.c deleted file mode 100644 index cacffa69f..000000000 --- a/src/modules/videostab/factory.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * factory.c -- the factory method interfaces - * Copyright (c) 2011 Marco Gittler - * - * 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 - -extern mlt_filter filter_videostab_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -extern mlt_filter filter_videostab2_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); - -static mlt_properties videostab_metadata( mlt_service_type type, const char *id, void *data ) -{ - char file[ PATH_MAX ]; - snprintf( file, PATH_MAX, "%s/videostab/filter_%s.yml", mlt_environment( "MLT_DATA" ), id ); - return mlt_properties_parse_yaml( file ); -} - -MLT_REPOSITORY -{ - MLT_REGISTER( filter_type, "videostab", filter_videostab_init ); - MLT_REGISTER_METADATA( filter_type, "videostab", videostab_metadata, NULL ); - MLT_REGISTER( filter_type, "videostab2", filter_videostab2_init ); - MLT_REGISTER_METADATA( filter_type, "videostab2", videostab_metadata, NULL ); - -} - - - diff --git a/src/modules/videostab/filter_videostab.c b/src/modules/videostab/filter_videostab.c deleted file mode 100644 index 4e71f200f..000000000 --- a/src/modules/videostab/filter_videostab.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * filter_imagestab.c -- video stabilization with code from http://vstab.sourceforge.net/ - * Copyright (c) 2011 Marco Gittler - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "stab/vector.h" -#include "stab/utils.h" -#include "stab/estimate.h" -#include "stab/resample.h" - - -typedef struct { - mlt_filter parent; - int initialized; - int* lanc_kernels; - es_ctx *es; - vc *pos_i; - vc *pos_h; - vc *pos_y; - rs_ctx *rs; -} *videostab; - -static void serialize_vectors( videostab self, mlt_position length ) -{ - mlt_geometry g = mlt_geometry_init(); - - if ( g ) - { - struct mlt_geometry_item_s item; - int i; - - // Initialize geometry item - item.key = item.f[0] = item.f[1] = 1; - item.f[2] = item.f[3] = item.f[4] = 0; - - for ( i = 0; i < length; i++ ) - { - // Set the geometry item - item.frame = i; - item.x = self->pos_h[i].x; - item.y = self->pos_h[i].y; - - // Add the geometry item - mlt_geometry_insert( g, &item ); - } - - // Put the analysis results in a property - mlt_geometry_set_length( g, length ); - mlt_properties_set_data( MLT_FILTER_PROPERTIES( self->parent ), "vectors", g, 0, - (mlt_destructor) mlt_geometry_close, (mlt_serialiser) mlt_geometry_serialise ); - } -} - -static void deserialize_vectors( videostab self, char *vectors, mlt_position length ) -{ - mlt_geometry g = mlt_geometry_init(); - - // Parse the property as a geometry - if ( g && !mlt_geometry_parse( g, vectors, length, -1, -1 ) ) - { - struct mlt_geometry_item_s item; - int i; - - // Copy the geometry items to a vc array for interp() - for ( i = 0; i < length; i++ ) - { - mlt_geometry_fetch( g, &item, i ); - self->pos_h[i].x = item.x; - self->pos_h[i].y = item.y; - } - } - else - { - mlt_log_warning( MLT_FILTER_SERVICE(self->parent), "failed to parse vectors\n" ); - } - - // We are done with this mlt_geometry - if ( g ) mlt_geometry_close( g ); -} - -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_frame_pop_service( frame ); - mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter)); - - // Disable consumer scaling - if (profile && profile->width && profile->height) { - *width = profile->width; - *height = profile->height; - } - - *format = mlt_image_rgb24; - mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "consumer_deinterlace", 1 ); - int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); - - if ( !error && *image ) - { - videostab self = filter->child; - mlt_position length = mlt_filter_get_length2( filter, frame ); - int h = *height; - int w = *width; - - // Service locks are for concurrency control - mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); - if ( !self->initialized ) - { - // Initialize our context - self->initialized = 1; - self->es = es_init( w, h ); - self->pos_i = (vc*) malloc( length * sizeof(vc) ); - self->pos_h = (vc*) malloc( length * sizeof(vc) ); - self->pos_y = (vc*) malloc( h * sizeof(vc) ); - self->rs = rs_init( w, h ); - } - char *vectors = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "vectors" ); - if ( !vectors ) - { - // Analyse - int pos = (int) mlt_filter_get_position( filter, frame ); - self->pos_i[pos] = vc_add( pos == 0 ? vc_zero() : self->pos_i[pos - 1], es_estimate( self->es, *image ) ); - - // On last frame - if ( pos == length - 1 ) - { - mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) ); - double fps = mlt_profile_fps( profile ); - - // Filter and store the results - hipass( self->pos_i, self->pos_h, length, fps ); - serialize_vectors( self, length ); - } - } else { - // Apply - if ( self->initialized != 2 ) - { - // Load analysis results from property - self->initialized = 2; - deserialize_vectors( self, vectors, length ); - } - if ( self->initialized == 2 ) - { - // Stabilize - float shutter_angle = mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame) , "shutterangle" ); - float pos = mlt_filter_get_position( filter, frame ); - int i; - - for (i = 0; i < h; i ++) - self->pos_y[i] = interp( self->lanc_kernels,self->pos_h, length, pos + (i - h / 2.0) * shutter_angle / (h * 360.0) ); - rs_resample( self->lanc_kernels,self->rs, *image, self->pos_y ); - } - } - mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); - } - 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; -} - -void filter_close( mlt_filter parent ) -{ - videostab self = parent->child; - if ( self->es ) es_free( self->es ); - free( self->pos_i ); - free( self->pos_h ); - free( self->pos_y ); - if ( self->rs ) rs_free( self->rs ); - if ( self->lanc_kernels) free_lanc_kernels(self->lanc_kernels); - free( self ); - parent->close = NULL; - parent->child = NULL; -} - -mlt_filter filter_videostab_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - videostab self = calloc( 1, sizeof(*self) ); - if ( self ) - { - mlt_filter parent = mlt_filter_new(); - if ( !parent ) - { - free( self ); - return NULL; - } - parent->child = self; - parent->close = filter_close; - parent->process = filter_process; - self->parent = parent; - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "shutterangle", "0" ); // 0 - 180 , default 0 - self->lanc_kernels=prepare_lanc_kernels(); - return parent; - } - return NULL; -} diff --git a/src/modules/videostab/filter_videostab.yml b/src/modules/videostab/filter_videostab.yml deleted file mode 100644 index be309cee0..000000000 --- a/src/modules/videostab/filter_videostab.yml +++ /dev/null @@ -1,44 +0,0 @@ -schema_version: 0.1 -type: filter -identifier: videostab -title: Videostab (*deprecated*) -copyright: Copyright (C) 2011 Marco Gittler -creator: Marco Gittler < -contributor: - - Dan Dennedy -version: 0.1 -license: GPL -language: en -url: http://vstab.sourceforge.net/ -creator: Marco Gittler -tags: - - Video -description: Stabilize Video (for wiggly video) -notes: > - This filter is deprecated and will eventually be removed; use the vidstab - filter instead. - This filter requires two passes. The first pass performs analysis and stores - the result in the vectors property. The second pass applies the vectors to - the image. - To use with melt, use 'melt ... -consumer xml:output.mlt all=1' for the - first pass. For the second pass, use output.mlt as the input. - -parameters: - - identifier: shutterangle - title: Shutterangle - type: integer - description: Angle that Images could be maximum rotated - readonly: no - required: no - minimum: 0 - maximum: 180 - default: 0 - mutable: yes - widget: spinner - - identifier: vectors - title: Vectors - type: geometry - description: > - A set of X/Y coordinates by which to adjust the image. - When this is not supplied, the filter computes the vectors and stores - them in this property when the last frame has been processed. diff --git a/src/modules/videostab/filter_videostab2.c b/src/modules/videostab/filter_videostab2.c deleted file mode 100644 index c6527291d..000000000 --- a/src/modules/videostab/filter_videostab2.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * filter_imagestab.c -- video stabilization with code from http://vstab.sourceforge.net/ - * Copyright (c) 2011 Marco Gittler - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "stabilize.h" -#include "transform_image.h" - -typedef struct { - StabData* stab; - TransformData* trans; - int initialized; - void* parent; -} videostab2_data; - -static void serialize_vectors( videostab2_data* self, mlt_position length ) -{ - mlt_geometry g = mlt_geometry_init(); - if ( g ) - { - struct mlt_geometry_item_s item; - mlt_position i; - - // Initialize geometry item - item.key = item.f[0] = item.f[1] = item.f[2] = item.f[3] = 1; - item.f[4] = 0; - - tlist* transform_data =self->stab->transs; - for ( i = 0; i < length; i++ ) - { - // Set the geometry item - item.frame = i; - if (transform_data){ - if ( transform_data->data){ - Transform* t=transform_data->data; - item.x=t->x; - item.y=t->y; - item.w=t->alpha; - item.h=t->zoom; - transform_data=transform_data->next; - } - } - // Add the geometry item - mlt_geometry_insert( g, &item ); - } - - // Put the analysis results in a property - mlt_geometry_set_length( g, length ); - mlt_properties_set_data( MLT_FILTER_PROPERTIES( (mlt_filter) self->parent ), "vectors", g, 0, - (mlt_destructor) mlt_geometry_close, (mlt_serialiser) mlt_geometry_serialise ); - } -} -// scale zoom implements the factor that the vetcors must be scaled since the vector is calculated for real with, now we need it for (scaled)width -Transform* deserialize_vectors( char *vectors, mlt_position length ,float scale_zoom ) -{ - mlt_geometry g = mlt_geometry_init(); - Transform* tx=NULL; - // Parse the property as a geometry - if ( g && !mlt_geometry_parse( g, vectors, length, -1, -1 ) ) - { - struct mlt_geometry_item_s item; - int i; - tx=calloc(1,sizeof(Transform)*length); - // Copy the geometry items to a vc array for interp() - for ( i = 0; i < length; i++ ) - { - mlt_geometry_fetch( g, &item, i ); - Transform t; - t.x=scale_zoom*item.x; - t.y=scale_zoom*item.y; - t.alpha=item.w; - t.zoom=scale_zoom*item.h; - t.extra=0; - tx[i]=t; - } - - } - else - { - //mlt_log_warning( NULL, "failed to parse vectors\n" ); - } - - // We are done with this mlt_geometry - if ( g ) mlt_geometry_close( g ); - return tx; -} - -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_frame_pop_service( frame ); - char *vectors = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "vectors" ); - mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter)); - - // Disable consumer scaling - if (profile && profile->width && profile->height) { - *width = profile->width; - *height = profile->height; - } - - *format = mlt_image_yuv422; - if (vectors) - *format= mlt_image_rgb24; - mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "consumer_deinterlace", 1 ); - int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); - - if ( !error && *image ) - { - videostab2_data* data = filter->child; - if ( data==NULL ) { // big error, abort - return 1; - } - mlt_position length = mlt_filter_get_length2( filter, frame ); - int h = *height; - int w = *width; - - // Service locks are for concurrency control - mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); - - // Handle signal from app to re-init data - if ( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "refresh" ) ) - { - mlt_properties_set( MLT_FILTER_PROPERTIES(filter) , "refresh", NULL ); - data->initialized = 0; - } - - if ( !vectors) { - if ( !data->initialized ) - { - // Initialize our context - data->initialized = 1; - data->stab->width=w; - data->stab->height=h; - if (*format==mlt_image_yuv420p) data->stab->framesize=w*h* 3/2;//( mlt_image_format_size ( *format, w,h , 0) ; // 3/2 =1 too small - if (*format==mlt_image_yuv422) data->stab->framesize=w*h; - data->stab->shakiness = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "shakiness" ); - data->stab->accuracy = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "accuracy" ); - data->stab->stepsize = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "stepsize" ); - data->stab->algo = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "algo" ); - data->stab->show = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "show" ); - data->stab->contrast_threshold = mlt_properties_get_double( MLT_FILTER_PROPERTIES(filter) , "mincontrast" ); - stabilize_configure(data->stab); - } - // Analyse - mlt_position pos = mlt_filter_get_position( filter, frame ); - stabilize_filter_video ( data->stab , *image, *format ); - - // On last frame - if ( pos == length - 1 ) - { - serialize_vectors( data , length ); - } - } - else - { - if ( data->initialized!=1 ) - { - char *interps = mlt_properties_get( MLT_FRAME_PROPERTIES( frame ), "rescale.interp" ); - - if ( data->initialized != 2 ) - { - // Load analysis results from property - data->initialized = 2; - - int interp = 2; // default to bilinear - float scale_zoom=1.0; - if ( *width != mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "meta.media.width" ) ) - scale_zoom = (float) *width / (float) mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "meta.media.width" ); - if ( strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 ) - interp = 0; - else if ( strcmp( interps, "tiles" ) == 0 || strcmp( interps, "fast_bilinear" ) == 0 ) - interp = 1; - - data->trans->interpoltype = interp; - data->trans->smoothing = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "smoothing" ); - data->trans->maxshift = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "maxshift" ); - data->trans->maxangle = mlt_properties_get_double( MLT_FILTER_PROPERTIES(filter), "maxangle" ); - data->trans->crop = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "crop" ); - data->trans->invert = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "invert" ); - data->trans->relative = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "relative" ); - data->trans->zoom = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "zoom" ); - data->trans->optzoom = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "optzoom" ); - data->trans->sharpen = mlt_properties_get_double( MLT_FILTER_PROPERTIES(filter), "sharpen" ); - - transform_configure(data->trans,w,h,*format ,*image, deserialize_vectors( vectors, length , scale_zoom ),length); - - } - if ( data->initialized == 2 ) - { - // Stabilize - float pos = mlt_filter_get_position( filter, frame ); - data->trans->current_trans=pos; - transform_filter_video(data->trans, *image, *format ); - - } - } - } - mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); - } - 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; -} - -static void filter_close( mlt_filter parent ) -{ - videostab2_data* data = parent->child; - if (data){ - if (data->stab) stabilize_stop(data->stab); - if (data->trans){ - free(data->trans->src); - free (data->trans); - } - free( data ); - } - parent->close = NULL; - parent->child = NULL; -} - -mlt_filter filter_videostab2_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - videostab2_data* data= calloc( 1, sizeof(videostab2_data)); - if ( data ) - { - data->stab = calloc( 1, sizeof(StabData) ); - if ( !data->stab ) - { - free( data ); - return NULL; - } - - data->trans = calloc( 1, sizeof (TransformData) ) ; - if ( !data->trans ) - { - free( data->stab ); - free( data ); - return NULL; - } - - mlt_filter parent = mlt_filter_new(); - if ( !parent ) - { - free( data->trans ); - free( data->stab ); - free( data ); - return NULL; - } - - parent->child = data; - parent->close = filter_close; - parent->process = filter_process; - data->parent = parent; - //properties for stabilize - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "shakiness", "4" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "accuracy", "4" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "stepsize", "6" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "algo", "1" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "mincontrast", "0.3" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "show", "0" ); - - //properties for transform - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "smoothing", "10" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "maxshift", "-1" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "maxangle", "-1" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "crop", "0" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "invert", "0" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "relative", "1" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "zoom", "0" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "optzoom", "1" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "sharpen", "0.8" ); - return parent; - } - return NULL; -} diff --git a/src/modules/videostab/filter_videostab2.yml b/src/modules/videostab/filter_videostab2.yml deleted file mode 100644 index 39d851c9a..000000000 --- a/src/modules/videostab/filter_videostab2.yml +++ /dev/null @@ -1,220 +0,0 @@ -schema_version: 0.1 -type: filter -identifier: videostab2 -title: Videostab2 (*deprecated*) -copyright: Copyright (C) 2011 Marco Gittler -creator: Marco Gittler -version: 0.1 -license: GPL -language: en -url: http://public.hronopik.de/vid.stab/ -tags: - - Video -description: Stabilize Video (for wiggly/rolling video) -notes: > - This filter is deprecated and will eventually be removed; use the vidstab - filter instead. - This filter requires two passes. The first pass performs analysis and stores - the result in the vectors property. The second pass applies the vectors to - the image. - To use with melt, use 'melt ... -consumer xml:output.mlt all=1' for the - first pass. For the second pass, use output.mlt as the input. - -parameters: - - identifier: vectors (transform) - title: Vectors - type: geometry - description: > - A set of X/Y coordinates by which to adjust the image. - When this is not supplied, the filter computes the vectors and stores - them in this property when the last frame has been processed. - - - identifier: shakiness - title: Shakiness - type: integer - description: How shaky is the video (analysis) - readonly: no - required: no - minimum: 1 - maximum: 10 - default: 4 - mutable: yes - widget: spinner - - - identifier: accuracy - title: Accuracy - type: integer - description: Accuracy of shakiness detection (analysis) - readonly: no - required: no - minimum: 1 - maximum: 15 - default: 4 - mutable: yes - widget: spinner - - - identifier: stepsize - title: Stepsize - type: integer - description: Step size of search process (analysis) - readonly: no - required: no - minimum: 0 - maximum: 100 - default: 6 - mutable: yes - widget: spinner - - - identifier: algo - title: Algorithm - type: integer - description: 0 = brute force (translation only), 1 = small measurement fields (analysis) - readonly: no - required: no - minimum: 0 - maximum: 1 - default: 1 - mutable: yes - widget: spinner - - - identifier: mincontrast - title: Minimum Contrast - type: float - description: Below this contrast, a field is discarded (analysis) - readonly: no - required: no - minimum: 0 - maximum: 1 - default: 0.3 - mutable: yes - widget: spinner - - - identifier: show - title: Show - type: integer - description: 0 = draw nothing, 1 or 2 = show fields and transforms (analysis) - readonly: no - required: no - minimum: 0 - maximum: 2 - default: 0 - mutable: yes - widget: spinner - - - identifier: smoothing - title: Smoothing - type: integer - description: number of frames for lowpass filtering (2N + 1 frames) (transform) - readonly: no - required: no - minimum: 0 - maximum: 100 - default: 10 - mutable: yes - widget: spinner - - - identifier: maxshift - title: Maxshift - type: integer - description: maximum translation, -1 = no limit (transform) - unit: pixels - readonly: no - required: no - minimum: -1 - maximum: 1000 - default: -1 - mutable: yes - widget: spinner - - - identifier: maxangle - title: Maxangle - type: float - description: max angle to rotate, -1 = no limit (transform) - unit: radians - readonly: no - required: no - minimum: -1 - maximum: 3.142 - default: -1 - mutable: yes - widget: spinner - - - identifier: crop - title: Crop - type: integer - description: 0 = keep border, 1 = black background (transform) - readonly: no - required: no - minimum: 0 - maximum: 1 - default: 0 - mutable: yes - widget: spinner - - - identifier: invert - title: Invert - type: integer - description: Invert transforms (transform) - readonly: no - required: no - minimum: 0 - maximum: 1 - default: 0 - mutable: yes - widget: spinner - - - identifier: relative - title: Relative Transform - type: integer - description: 0 = absolute, 1 = relative (transform) - readonly: no - required: no - minimum: 0 - maximum: 1 - default: 1 - mutable: yes - widget: spinner - - - identifier: zoom - title: Zoom - type: integer - description: additional zoom amount (transform) - unit: percent - readonly: no - required: no - minimum: -500 - maximum: 500 - default: 0 - mutable: yes - widget: spinner - - - identifier: optzoom - title: Optimal Zoom - type: integer - description: automatically determine optimal zoom (transform) - readonly: no - required: no - minimum: 0 - maximum: 1 - default: 1 - mutable: yes - widget: spinner - - - identifier: sharpen - title: Sharpen Image - type: float - description: amount of sharpening (transform) - readonly: no - required: no - minimum: 0 - maximum: 10 - default: 0.8 - mutable: yes - widget: spinner - - - identifier: refresh - description: > - Applications should set this when it updates a transform parameter. - type: integer - minimum: 0 - maximum: 1 diff --git a/src/modules/videostab/gpl b/src/modules/videostab/gpl deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/modules/videostab/stab/estimate.c b/src/modules/videostab/stab/estimate.c deleted file mode 100644 index b80ab510d..000000000 --- a/src/modules/videostab/stab/estimate.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Video stabilizer - * - * Copyright (c) 2008 Lenny - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(_WIN32) && !defined(__NetBSD__) && !defined(__OpenBSD__) -#include -#endif - -#include "estimate.h" -#include "vector.h" -#include "utils.h" - -#if !defined(MAXFLOAT) -#define MAXFLOAT HUGE_VAL -#endif - -es_ctx *es_init(int nc, int nr) { - - es_ctx *es = (es_ctx *)malloc(sizeof(es_ctx)); - - es->tc = KLTCreateTrackingContext(); - - es->tc->sequentialMode = TRUE; - es->tc->min_eigenvalue = 8; - es->tc->verbose = FALSE; - - KLTChangeTCPyramid(es->tc, 31); - - KLTUpdateTCBorder(es->tc); - - es->fr[0] = (KLT_PixelType *)malloc(nc * nr * sizeof(KLT_PixelType)); - es->fr[1] = (KLT_PixelType *)malloc(nc * nr * sizeof(KLT_PixelType)); - - es->fl = KLTCreateFeatureList(64); - - es->dv = (vc *)malloc(64 * sizeof(vc)); - es->nv = 0; - - es->nc = nc; - es->nr = nr; - - es->ff = FALSE; - - return es; -} - -vc es_estimate(es_ctx *es, unsigned char *fr) { - - KLT_PixelType *t; - int is, id; - - t = es->fr[0]; es->fr[0] = es->fr[1]; es->fr[1] = t; - - for (is = 0, id = 0; id < es->nc * es->nr; is += 3, id ++) - es->fr[1][id] = (fr[is + 0] * 30 + fr[is + 1] * 59 + fr[is + 2] * 11) / 100; - - if (es->ff == FALSE) { - - es->ff = TRUE; - - } else { - - vc bv = vc_set(0.0, 0.0); - float be = MAXFLOAT; - - int i, i2; - - KLTSelectGoodFeatures( - es->tc, es->fr[0], es->nc, es->nr, es->fl - ); - - for (i = 0; i < es->fl->nFeatures; i ++) - es->dv[i] = vc_set(es->fl->feature[i]->x, es->fl->feature[i]->y); - - KLTTrackFeatures( - es->tc, es->fr[0], es->fr[1], es->nc, es->nr, es->fl - ); - - es->nv = 0; - - for (i = 0; i < es->fl->nFeatures; i ++) { - - if (es->fl->feature[i]->val == KLT_TRACKED) { - - es->dv[es->nv] = vc_set( - es->fl->feature[i]->x - es->dv[i].x, - es->fl->feature[i]->y - es->dv[i].y - ); - - es->nv ++; - } - } - - for (i = 0; i < es->nv; i ++) { - - float ce = 0.0; - - for (i2 = 0; i2 < es->nv; i2 ++) - ce += vc_len(vc_sub(es->dv[i2], es->dv[i])); - - if (ce < be) { - - bv = es->dv[i]; - be = ce; - } - } - - return bv; - } - - return vc_zero(); -} - -void es_free(es_ctx *es) { - - free(es->dv); - - free(es->fr[0]); - free(es->fr[1]); - - KLTFreeFeatureList(es->fl); - KLTFreeTrackingContext(es->tc); - - free(es); -} - diff --git a/src/modules/videostab/stab/estimate.h b/src/modules/videostab/stab/estimate.h deleted file mode 100644 index 282c499ae..000000000 --- a/src/modules/videostab/stab/estimate.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef ESTIMATE_H -#define ESTIMATE_H - -#include "klt/klt.h" - -#include "vector.h" - -typedef struct { - - KLT_TrackingContext tc; - KLT_PixelType *fr[2]; - KLT_FeatureList fl; - - vc *dv; - int nv; - - int nc, nr; - - int ff; - -} es_ctx; - -es_ctx *es_init(int, int); - -vc es_estimate(es_ctx *, unsigned char *); - -void es_free(es_ctx *); - -#endif - diff --git a/src/modules/videostab/stab/klt/base.h b/src/modules/videostab/stab/klt/base.h deleted file mode 100644 index 35d709447..000000000 --- a/src/modules/videostab/stab/klt/base.h +++ /dev/null @@ -1,38 +0,0 @@ -/********************************************************************* - * base.h - *********************************************************************/ - -#ifndef _BASE_H_ -#define _BASE_H_ - -#ifndef uchar -#define uchar unsigned char -#endif - -#ifndef schar -#define schar signed char -#endif - -#ifndef uint -#define uint unsigned int -#endif - -#ifndef ushort -#define ushort unsigned short -#endif - -#ifndef ulong -#define ulong unsigned long -#endif - -#ifndef max -#define max(a,b) ((a) > (b) ? (a) : (b)) -#endif -#ifndef min -#define min(a,b) ((a) < (b) ? (a) : (b)) -#endif -#define max3(a,b,c) ((a) > (b) ? max((a),(c)) : max((b),(c))) -#define min3(a,b,c) ((a) < (b) ? min((a),(c)) : min((b),(c))) - -#endif - diff --git a/src/modules/videostab/stab/klt/convolve.c b/src/modules/videostab/stab/klt/convolve.c deleted file mode 100644 index f8107a279..000000000 --- a/src/modules/videostab/stab/klt/convolve.c +++ /dev/null @@ -1,279 +0,0 @@ -/********************************************************************* - * convolve.c - *********************************************************************/ - -/* Standard includes */ -#include -#include /* malloc(), realloc() */ - -/* Our includes */ -#include "base.h" -#include "error.h" -#include "convolve.h" -#include "klt_util.h" /* printing */ - -#define MAX_KERNEL_WIDTH 71 - - -typedef struct { - int width; - float data[MAX_KERNEL_WIDTH]; -} ConvolutionKernel; - -/* Kernels */ -ConvolutionKernel gauss_kernel; -ConvolutionKernel gaussderiv_kernel; -float sigma_last = -10.0; - - -/********************************************************************* - * _KLTToFloatImage - * - * Given a pointer to image data (probably unsigned chars), copy - * data to a float image. - */ - -void _KLTToFloatImage( - KLT_PixelType *img, - int ncols, int nrows, - _KLT_FloatImage floatimg) -{ - KLT_PixelType *ptrend = img + ncols*nrows; - float *ptrout = floatimg->data; - - floatimg->ncols = ncols; - floatimg->nrows = nrows; - - while (img < ptrend) *ptrout++ = (float) *img++; -} - - -/********************************************************************* - * _computeKernels - */ - -void _computeKernels( - float sigma, - ConvolutionKernel *gauss, - ConvolutionKernel *gaussderiv) -{ - const float factor = 0.01f; /* for truncating tail */ - int i; - - /* Compute kernels, and automatically determine widths */ - { - const int hw = MAX_KERNEL_WIDTH / 2; - float max_gauss = 1.0f, max_gaussderiv = (float) (sigma*exp(-0.5f)); - - /* Compute gauss and deriv */ - for (i = -hw ; i <= hw ; i++) { - gauss->data[i+hw] = (float) exp(-i*i / (2*sigma*sigma)); - gaussderiv->data[i+hw] = -i * gauss->data[i+hw]; - } - - /* Compute widths */ - gauss->width = MAX_KERNEL_WIDTH; - for (i = -hw ; fabs(gauss->data[i+hw] / max_gauss) < factor ; - i++, gauss->width -= 2); - gaussderiv->width = MAX_KERNEL_WIDTH; - for (i = -hw ; fabs(gaussderiv->data[i+hw] / max_gaussderiv) < factor ; - i++, gaussderiv->width -= 2); - if (gauss->width == MAX_KERNEL_WIDTH || - gaussderiv->width == MAX_KERNEL_WIDTH) - KLTError("(_computeKernels) MAX_KERNEL_WIDTH %d is too small for " - "a sigma of %f", MAX_KERNEL_WIDTH, sigma); - } - - /* Shift if width less than MAX_KERNEL_WIDTH */ - for (i = 0 ; i < gauss->width ; i++) - gauss->data[i] = gauss->data[i+(MAX_KERNEL_WIDTH-gauss->width)/2]; - for (i = 0 ; i < gaussderiv->width ; i++) - gaussderiv->data[i] = gaussderiv->data[i+(MAX_KERNEL_WIDTH-gaussderiv->width)/2]; - /* Normalize gauss and deriv */ - { - const int hw = gaussderiv->width / 2; - float den; - - den = 0.0; - for (i = 0 ; i < gauss->width ; i++) den += gauss->data[i]; - for (i = 0 ; i < gauss->width ; i++) gauss->data[i] /= den; - den = 0.0; - for (i = -hw ; i <= hw ; i++) den -= i*gaussderiv->data[i+hw]; - for (i = -hw ; i <= hw ; i++) gaussderiv->data[i+hw] /= den; - } - - sigma_last = sigma; -} - - -/********************************************************************* - * _KLTGetKernelWidths - * - */ - -void _KLTGetKernelWidths( - float sigma, - int *gauss_width, - int *gaussderiv_width) -{ - _computeKernels(sigma, &gauss_kernel, &gaussderiv_kernel); - *gauss_width = gauss_kernel.width; - *gaussderiv_width = gaussderiv_kernel.width; -} - - -/********************************************************************* - * _convolveImageHoriz - */ - -void _convolveImageHoriz( - _KLT_FloatImage imgin, - ConvolutionKernel kernel, - _KLT_FloatImage imgout) -{ - float *ptrrow = imgin->data; /* Points to row's first pixel */ - float *ptrout = imgout->data, /* Points to next output pixel */ - *ppp; - float sum; - int radius = kernel.width / 2; - int ncols = imgin->ncols, nrows = imgin->nrows; - int i, j, k; - - /* For each row, do ... */ - for (j = 0 ; j < nrows ; j++) { - - /* Zero leftmost columns */ - for (i = 0 ; i < radius ; i++) - *ptrout++ = 0.0; - - /* Convolve middle columns with kernel */ - for ( ; i < ncols - radius ; i++) { - ppp = ptrrow + i - radius; - sum = 0.0; - for (k = kernel.width-1 ; k >= 0 ; k--) - sum += *ppp++ * kernel.data[k]; - *ptrout++ = sum; - } - - /* Zero rightmost columns */ - for ( ; i < ncols ; i++) - *ptrout++ = 0.0; - - ptrrow += ncols; - } -} - - -/********************************************************************* - * _convolveImageVert - */ - -void _convolveImageVert( - _KLT_FloatImage imgin, - ConvolutionKernel kernel, - _KLT_FloatImage imgout) -{ - float *ptrcol = imgin->data; /* Points to row's first pixel */ - float *ptrout = imgout->data, /* Points to next output pixel */ - *ppp; - float sum; - int radius = kernel.width / 2; - int ncols = imgin->ncols, nrows = imgin->nrows; - int i, j, k; - - /* For each column, do ... */ - for (i = 0 ; i < ncols ; i++) { - - /* Zero topmost rows */ - for (j = 0 ; j < radius ; j++) { - *ptrout = 0.0; - ptrout += ncols; - } - - /* Convolve middle rows with kernel */ - for ( ; j < nrows - radius ; j++) { - ppp = ptrcol + ncols * (j - radius); - sum = 0.0; - for (k = kernel.width-1 ; k >= 0 ; k--) { - sum += *ppp * kernel.data[k]; - ppp += ncols; - } - *ptrout = sum; - ptrout += ncols; - } - - /* Zero bottommost rows */ - for ( ; j < nrows ; j++) { - *ptrout = 0.0; - ptrout += ncols; - } - - ptrcol++; - ptrout -= nrows * ncols - 1; - } -} - - -/********************************************************************* - * _convolveSeparate - */ - -void _convolveSeparate( - _KLT_FloatImage imgin, - ConvolutionKernel horiz_kernel, - ConvolutionKernel vert_kernel, - _KLT_FloatImage imgout) -{ - /* Create temporary image */ - _KLT_FloatImage tmpimg; - tmpimg = _KLTCreateFloatImage(imgin->ncols, imgin->nrows); - - /* Do convolution */ - _convolveImageHoriz(imgin, horiz_kernel, tmpimg); - - _convolveImageVert(tmpimg, vert_kernel, imgout); - - /* Free memory */ - _KLTFreeFloatImage(tmpimg); -} - - -/********************************************************************* - * _KLTComputeGradients - */ - -void _KLTComputeGradients( - _KLT_FloatImage img, - float sigma, - _KLT_FloatImage gradx, - _KLT_FloatImage grady) -{ - - /* Compute kernels, if necessary */ - if (fabs(sigma - sigma_last) > 0.05) - _computeKernels(sigma, &gauss_kernel, &gaussderiv_kernel); - - _convolveSeparate(img, gaussderiv_kernel, gauss_kernel, gradx); - _convolveSeparate(img, gauss_kernel, gaussderiv_kernel, grady); - -} - - -/********************************************************************* - * _KLTComputeSmoothedImage - */ - -void _KLTComputeSmoothedImage( - _KLT_FloatImage img, - float sigma, - _KLT_FloatImage smooth) -{ - /* Compute kernel, if necessary; gauss_deriv is not used */ - if (fabs(sigma - sigma_last) > 0.05) - _computeKernels(sigma, &gauss_kernel, &gaussderiv_kernel); - - _convolveSeparate(img, gauss_kernel, gauss_kernel, smooth); -} - - - diff --git a/src/modules/videostab/stab/klt/convolve.h b/src/modules/videostab/stab/klt/convolve.h deleted file mode 100644 index 6043a7e25..000000000 --- a/src/modules/videostab/stab/klt/convolve.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************************* - * convolve.h - *********************************************************************/ - -#ifndef _CONVOLVE_H_ -#define _CONVOLVE_H_ - -#include "klt.h" -#include "klt_util.h" - -void _KLTToFloatImage( - KLT_PixelType *img, - int ncols, int nrows, - _KLT_FloatImage floatimg); - -void _KLTComputeGradients( - _KLT_FloatImage img, - float sigma, - _KLT_FloatImage gradx, - _KLT_FloatImage grady); - -void _KLTGetKernelWidths( - float sigma, - int *gauss_width, - int *gaussderiv_width); - -void _KLTComputeSmoothedImage( - _KLT_FloatImage img, - float sigma, - _KLT_FloatImage smooth); - -#endif diff --git a/src/modules/videostab/stab/klt/error.c b/src/modules/videostab/stab/klt/error.c deleted file mode 100644 index 5cb4ee4ed..000000000 --- a/src/modules/videostab/stab/klt/error.c +++ /dev/null @@ -1,55 +0,0 @@ -/********************************************************************* - * error.c - * - * Error and warning messages, and system commands. - *********************************************************************/ - - -/* Standard includes */ -#include -#include -#include -#include - -/********************************************************************* - * KLTError - * - * Prints an error message and dies. - * - * INPUTS - * exactly like printf - */ - -void KLTError(char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - mlt_log_error(NULL, "KLT Error: "); - mlt_log_error(NULL, fmt, args); - mlt_log_error(NULL, "\n"); - va_end(args); -} - - -/********************************************************************* - * KLTWarning - * - * Prints a warning message. - * - * INPUTS - * exactly like printf - */ - -void KLTWarning(char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - fprintf(stderr, "KLT Warning: "); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - fflush(stderr); - va_end(args); -} - diff --git a/src/modules/videostab/stab/klt/error.h b/src/modules/videostab/stab/klt/error.h deleted file mode 100644 index 4dac13651..000000000 --- a/src/modules/videostab/stab/klt/error.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************* - * error.h - *********************************************************************/ - -#ifndef _ERROR_H_ -#define _ERROR_H_ - -#include -#include - -void KLTError(char *fmt, ...); -void KLTWarning(char *fmt, ...); - -#endif - diff --git a/src/modules/videostab/stab/klt/klt.c b/src/modules/videostab/stab/klt/klt.c deleted file mode 100644 index 76ed461c6..000000000 --- a/src/modules/videostab/stab/klt/klt.c +++ /dev/null @@ -1,342 +0,0 @@ -/********************************************************************* - * klt.c - * - * Kanade-Lucas-Tomasi tracker - *********************************************************************/ - -/* Standard includes */ -#include /* logf() */ -#include /* malloc() */ - -/* Our includes */ -#include "base.h" -#include "convolve.h" -#include "error.h" -#include "klt.h" -#include "pyramid.h" - -/********************************************************************* - * KLTCreateTrackingContext - * - */ - -KLT_TrackingContext KLTCreateTrackingContext() -{ - KLT_TrackingContext tc = NULL; - - /* Allocate memory */ - tc = (KLT_TrackingContext) calloc(1, sizeof(KLT_TrackingContextRec)); - - /* Set values to default values */ - tc->mindist = 10; - tc->window_width = 7; - tc->window_height = 7; - tc->sequentialMode = FALSE; - tc->smoothBeforeSelecting = TRUE; - tc->min_eigenvalue = 1; - tc->min_determinant = 0.01; - tc->max_iterations = 10; - tc->min_displacement = 0.1; - tc->max_residue = 10.0; - tc->grad_sigma = 1.0; - tc->smooth_sigma_fact = 0.1; - tc->pyramid_sigma_fact = 0.9; - tc->step_factor = 1.0; - tc->nSkippedPixels = 0; - tc->pyramid_last = NULL; - tc->pyramid_last_gradx = NULL; - tc->pyramid_last_grady = NULL; - tc->verbose = TRUE; - - /* Change nPyramidLevels and subsampling */ - KLTChangeTCPyramid(tc, 31); - - /* Update border, which is dependent upon */ - /* smooth_sigma_fact, pyramid_sigma_fact, window_size, and subsampling */ - KLTUpdateTCBorder(tc); - - return(tc); -} - -/********************************************************************* - * KLTCreateFeatureList - * - */ - -KLT_FeatureList KLTCreateFeatureList( - int nFeatures) -{ - KLT_FeatureList fl; - KLT_Feature first; - int nbytes = sizeof(KLT_FeatureListRec) + - nFeatures * sizeof(KLT_Feature) + - nFeatures * sizeof(KLT_FeatureRec); - int i; - - /* Allocate memory for feature list */ - fl = (KLT_FeatureList) malloc(nbytes); - - /* Set parameters */ - fl->nFeatures = nFeatures; - - /* Set pointers */ - fl->feature = (KLT_Feature *) (fl + 1); - first = (KLT_Feature) (fl->feature + nFeatures); - for (i = 0 ; i < nFeatures ; i++) - fl->feature[i] = first + i; - - /* Return feature list */ - return(fl); -} - -/********************************************************************* - * KLTPrintTrackingContext - */ - -void KLTPrintTrackingContext( - KLT_TrackingContext tc) -{ - fprintf(stderr, "\n\nTracking context:\n\n"); - fprintf(stderr, "\tmindist = %d\n", tc->mindist); - fprintf(stderr, "\twindow_width = %d\n", tc->window_width); - fprintf(stderr, "\twindow_height = %d\n", tc->window_height); - fprintf(stderr, "\tsequentialMode = %s\n", - tc->sequentialMode ? "TRUE" : "FALSE"); - fprintf(stderr, "\tsmoothBeforeSelecting = %s\n", - tc->smoothBeforeSelecting ? "TRUE" : "FALSE"); - - fprintf(stderr, "\tmin_eigenvalue = %d\n", tc->min_eigenvalue); - fprintf(stderr, "\tmin_determinant = %f\n", tc->min_determinant); - fprintf(stderr, "\tmin_displacement = %f\n", tc->min_displacement); - fprintf(stderr, "\tmax_iterations = %d\n", tc->max_iterations); - fprintf(stderr, "\tmax_residue = %f\n", tc->max_residue); - fprintf(stderr, "\tgrad_sigma = %f\n", tc->grad_sigma); - fprintf(stderr, "\tsmooth_sigma_fact = %f\n", tc->smooth_sigma_fact); - fprintf(stderr, "\tpyramid_sigma_fact = %f\n", tc->pyramid_sigma_fact); - fprintf(stderr, "\tnSkippedPixels = %d\n", tc->nSkippedPixels); - fprintf(stderr, "\tborderx = %d\n", tc->borderx); - fprintf(stderr, "\tbordery = %d\n", tc->bordery); - fprintf(stderr, "\tnPyramidLevels = %d\n", tc->nPyramidLevels); - fprintf(stderr, "\tsubsampling = %d\n", tc->subsampling); - - fprintf(stderr, "\n\tpyramid_last = %s\n", (tc->pyramid_last!=NULL) ? - "points to old image" : "NULL"); - fprintf(stderr, "\tpyramid_last_gradx = %s\n", - (tc->pyramid_last_gradx!=NULL) ? - "points to old image" : "NULL"); - fprintf(stderr, "\tpyramid_last_grady = %s\n", - (tc->pyramid_last_grady!=NULL) ? - "points to old image" : "NULL"); - fprintf(stderr, "\n\n"); -} - - -/********************************************************************* - * KLTChangeTCPyramid - * - */ - -void KLTChangeTCPyramid( - KLT_TrackingContext tc, - int search_range) -{ - float window_halfwidth; - float subsampling; - - /* Check window size (and correct if necessary) */ - if (tc->window_width % 2 != 1) { - tc->window_width = tc->window_width+1; - KLTWarning("(KLTChangeTCPyramid) Window width must be odd. " - "Changing to %d.\n", tc->window_width); - } - if (tc->window_height % 2 != 1) { - tc->window_height = tc->window_height+1; - KLTWarning("(KLTChangeTCPyramid) Window height must be odd. " - "Changing to %d.\n", tc->window_height); - } - if (tc->window_width < 3) { - tc->window_width = 3; - KLTWarning("(KLTChangeTCPyramid) Window width must be at least three. \n" - "Changing to %d.\n", tc->window_width); - } - if (tc->window_height < 3) { - tc->window_height = 3; - KLTWarning("(KLTChangeTCPyramid) Window height must be at least three. \n" - "Changing to %d.\n", tc->window_height); - } - window_halfwidth = min(tc->window_width,tc->window_height)/2.0f; - - subsampling = ((float) search_range) / window_halfwidth; - - if (subsampling < 1.0) { /* 1.0 = 0+1 */ - tc->nPyramidLevels = 1; - } else if (subsampling <= 3.0) { /* 3.0 = 2+1 */ - tc->nPyramidLevels = 2; - tc->subsampling = 2; - } else if (subsampling <= 5.0) { /* 5.0 = 4+1 */ - tc->nPyramidLevels = 2; - tc->subsampling = 4; - } else if (subsampling <= 9.0) { /* 9.0 = 8+1 */ - tc->nPyramidLevels = 2; - tc->subsampling = 8; - } else { - /* The following lines are derived from the formula: - search_range = - window_halfwidth * \sum_{i=0}^{nPyramidLevels-1} 8^i, - which is the same as: - search_range = - window_halfwidth * (8^nPyramidLevels - 1)/(8 - 1). - Then, the value is rounded up to the nearest integer. */ - float val = (float) (log(7.0*subsampling+1.0)/log(8.0)); - tc->nPyramidLevels = (int) (val + 0.99); - tc->subsampling = 8; - } -} - - -/********************************************************************* - * NOTE: Manually must ensure consistency with _KLTComputePyramid() - */ - -float _pyramidSigma( - KLT_TrackingContext tc) -{ - return (tc->pyramid_sigma_fact * tc->subsampling); -} - - -/********************************************************************* - * Updates border, which is dependent upon - * smooth_sigma_fact, pyramid_sigma_fact, window_size, and subsampling - */ - -void KLTUpdateTCBorder( - KLT_TrackingContext tc) -{ - float val; - int pyramid_gauss_hw; - int smooth_gauss_hw; - int gauss_width, gaussderiv_width; - int num_levels = tc->nPyramidLevels; - int n_invalid_pixels; - int window_hw; - int ss = tc->subsampling; - int ss_power; - int border; - int i; - - /* Check window size (and correct if necessary) */ - if (tc->window_width % 2 != 1) { - tc->window_width = tc->window_width+1; - KLTWarning("(KLTUpdateTCBorder) Window width must be odd. " - "Changing to %d.\n", tc->window_width); - } - if (tc->window_height % 2 != 1) { - tc->window_height = tc->window_height+1; - KLTWarning("(KLTUpdateTCBorder) Window height must be odd. " - "Changing to %d.\n", tc->window_height); - } - if (tc->window_width < 3) { - tc->window_width = 3; - KLTWarning("(KLTUpdateTCBorder) Window width must be at least three. \n" - "Changing to %d.\n", tc->window_width); - } - if (tc->window_height < 3) { - tc->window_height = 3; - KLTWarning("(KLTUpdateTCBorder) Window height must be at least three. \n" - "Changing to %d.\n", tc->window_height); - } - window_hw = max(tc->window_width, tc->window_height)/2; - - /* Find widths of convolution windows */ - _KLTGetKernelWidths(_KLTComputeSmoothSigma(tc), - &gauss_width, &gaussderiv_width); - smooth_gauss_hw = gauss_width/2; - _KLTGetKernelWidths(_pyramidSigma(tc), - &gauss_width, &gaussderiv_width); - pyramid_gauss_hw = gauss_width/2; - - /* Compute the # of invalid pixels at each level of the pyramid. - n_invalid_pixels is computed with respect to the ith level - of the pyramid. So, e.g., if n_invalid_pixels = 5 after - the first iteration, then there are 5 invalid pixels in - level 1, which translated means 5*subsampling invalid pixels - in the original level 0. */ - n_invalid_pixels = smooth_gauss_hw; - for (i = 1 ; i < num_levels ; i++) { - val = ((float) n_invalid_pixels + pyramid_gauss_hw) / ss; - n_invalid_pixels = (int) (val + 0.99); /* Round up */ - } - - /* ss_power = ss^(num_levels-1) */ - ss_power = 1; - for (i = 1 ; i < num_levels ; i++) - ss_power *= ss; - - /* Compute border by translating invalid pixels back into */ - /* original image */ - border = (n_invalid_pixels + window_hw) * ss_power; - - tc->borderx = border; - tc->bordery = border; -} - - -/********************************************************************* - * KLTFreeTrackingContext - * KLTFreeFeatureList - * KLTFreeFeatureHistory - * KLTFreeFeatureTable - */ - -void KLTFreeTrackingContext( - KLT_TrackingContext tc) -{ - if (tc->pyramid_last) - _KLTFreePyramid((_KLT_Pyramid) tc->pyramid_last); - if (tc->pyramid_last_gradx) - _KLTFreePyramid((_KLT_Pyramid) tc->pyramid_last_gradx); - if (tc->pyramid_last_grady) - _KLTFreePyramid((_KLT_Pyramid) tc->pyramid_last_grady); - free(tc); -} - -void KLTFreeFeatureList(KLT_FeatureList fl) { - - free(fl); -} - -/********************************************************************* - * KLTStopSequentialMode - */ - -void KLTStopSequentialMode( - KLT_TrackingContext tc) -{ - tc->sequentialMode = FALSE; - _KLTFreePyramid((_KLT_Pyramid) tc->pyramid_last); - _KLTFreePyramid((_KLT_Pyramid) tc->pyramid_last_gradx); - _KLTFreePyramid((_KLT_Pyramid) tc->pyramid_last_grady); - tc->pyramid_last = NULL; - tc->pyramid_last_gradx = NULL; - tc->pyramid_last_grady = NULL; -} - - -/********************************************************************* - * KLTCountRemainingFeatures - */ - -int KLTCountRemainingFeatures( - KLT_FeatureList fl) -{ - int count = 0; - int i; - - for (i = 0 ; i < fl->nFeatures ; i++) - if (fl->feature[i]->val >= 0) - count++; - - return count; -} - diff --git a/src/modules/videostab/stab/klt/klt.h b/src/modules/videostab/stab/klt/klt.h deleted file mode 100644 index f583f6b3c..000000000 --- a/src/modules/videostab/stab/klt/klt.h +++ /dev/null @@ -1,143 +0,0 @@ -/********************************************************************* - * klt.h - * - * Kanade-Lucas-Tomasi tracker - *********************************************************************/ - -#ifndef _KLT_H_ -#define _KLT_H_ - -typedef float KLT_locType; -typedef unsigned char KLT_PixelType; - -#define KLT_BOOL int - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -#ifndef NULL -#define NULL 0 -#endif - -#define KLT_TRACKED 0 -#define KLT_NOT_FOUND -1 -#define KLT_SMALL_DET -2 -#define KLT_MAX_ITERATIONS -3 -#define KLT_OOB -4 -#define KLT_LARGE_RESIDUE -5 - -#include "klt_util.h" /* for affine mapping */ - -/******************* - * Structures - */ - -typedef struct { - /* Available to user */ - int mindist; /* min distance b/w features */ - int window_width, window_height; - KLT_BOOL sequentialMode; /* whether to save most recent image to save time */ - /* can set to TRUE manually, but don't set to */ - /* FALSE manually */ - KLT_BOOL smoothBeforeSelecting; /* whether to smooth image before */ - /* selecting features */ - - /* Available, but hopefully can ignore */ - int min_eigenvalue; /* smallest eigenvalue allowed for selecting */ - float min_determinant; /* th for determining lost */ - float min_displacement; /* th for stopping tracking when pixel changes little */ - int max_iterations; /* th for stopping tracking when too many iterations */ - float max_residue; /* th for stopping tracking when residue is large */ - float grad_sigma; - float smooth_sigma_fact; - float pyramid_sigma_fact; - float step_factor; /* size of Newton steps; 2.0 comes from equations, 1.0 seems to avoid overshooting */ - int nSkippedPixels; /* # of pixels skipped when finding features */ - int borderx; /* border in which features will not be found */ - int bordery; - int nPyramidLevels; /* computed from search_ranges */ - int subsampling; /* " */ - - /* User must not touch these */ - void *pyramid_last; - void *pyramid_last_gradx; - void *pyramid_last_grady; - - int verbose; - -} KLT_TrackingContextRec, *KLT_TrackingContext; - -typedef struct { - KLT_locType x; - KLT_locType y; - int val; -} KLT_FeatureRec, *KLT_Feature; - -typedef struct { - int nFeatures; - KLT_Feature *feature; -} KLT_FeatureListRec, *KLT_FeatureList; - -typedef struct { - int nFrames; - KLT_Feature *feature; -} KLT_FeatureHistoryRec, *KLT_FeatureHistory; - -typedef struct { - int nFrames; - int nFeatures; - KLT_Feature **feature; -} KLT_FeatureTableRec, *KLT_FeatureTable; - -/******************* - * Functions - */ - -/* Create */ -KLT_TrackingContext KLTCreateTrackingContext(); -KLT_FeatureList KLTCreateFeatureList(int); - -/* Free */ -void KLTFreeTrackingContext(KLT_TrackingContext); -void KLTFreeFeatureList(KLT_FeatureList); - -/* Processing */ -void KLTSelectGoodFeatures( - KLT_TrackingContext tc, - KLT_PixelType *img, - int ncols, - int nrows, - KLT_FeatureList fl); -void KLTTrackFeatures( - KLT_TrackingContext tc, - KLT_PixelType *img1, - KLT_PixelType *img2, - int ncols, - int nrows, - KLT_FeatureList fl); -void KLTReplaceLostFeatures( - KLT_TrackingContext tc, - KLT_PixelType *img, - int ncols, - int nrows, - KLT_FeatureList fl); - -/* Utilities */ -int KLTCountRemainingFeatures( - KLT_FeatureList fl); -void KLTPrintTrackingContext( - KLT_TrackingContext tc); -void KLTChangeTCPyramid( - KLT_TrackingContext tc, - int search_range); -void KLTUpdateTCBorder( - KLT_TrackingContext tc); -void KLTStopSequentialMode( - KLT_TrackingContext tc); -float _KLTComputeSmoothSigma( - KLT_TrackingContext tc); - -#endif - diff --git a/src/modules/videostab/stab/klt/klt_util.c b/src/modules/videostab/stab/klt/klt_util.c deleted file mode 100644 index 36a357351..000000000 --- a/src/modules/videostab/stab/klt/klt_util.c +++ /dev/null @@ -1,52 +0,0 @@ -/********************************************************************* - * klt_util.c - *********************************************************************/ - -/* Standard includes */ -#include -#include - -/* Our includes */ -#include "base.h" -#include "error.h" -#include "klt.h" -#include "klt_util.h" - -/*********************************************************************/ - -float _KLTComputeSmoothSigma( - KLT_TrackingContext tc) -{ - return (tc->smooth_sigma_fact * max(tc->window_width, tc->window_height)); -} - - -/********************************************************************* - * _KLTCreateFloatImage - */ - -_KLT_FloatImage _KLTCreateFloatImage(int ncols, int nrows) { - - int nbytes = sizeof(_KLT_FloatImageRec) + ncols * nrows * sizeof(float); - - _KLT_FloatImage floatimg; - - floatimg = (_KLT_FloatImage)malloc(nbytes); - floatimg->ncols = ncols; - floatimg->nrows = nrows; - floatimg->data = (float *)(floatimg + 1); - - return(floatimg); -} - - -/********************************************************************* - * _KLTFreeFloatImage - */ - -void _KLTFreeFloatImage( - _KLT_FloatImage floatimg) -{ - free(floatimg); -} - diff --git a/src/modules/videostab/stab/klt/klt_util.h b/src/modules/videostab/stab/klt/klt_util.h deleted file mode 100644 index bb1a7432e..000000000 --- a/src/modules/videostab/stab/klt/klt_util.h +++ /dev/null @@ -1,28 +0,0 @@ -/********************************************************************* - * klt_util.h - *********************************************************************/ - -#ifndef _KLT_UTIL_H_ -#define _KLT_UTIL_H_ - -typedef struct { - int ncols; - int nrows; - float *data; -} _KLT_FloatImageRec, *_KLT_FloatImage; - -_KLT_FloatImage _KLTCreateFloatImage( - int ncols, - int nrows); - -void _KLTFreeFloatImage( - _KLT_FloatImage); - -void _KLTPrintSubFloatImage( - _KLT_FloatImage floatimg, - int x0, int y0, - int width, int height); - -#endif - - diff --git a/src/modules/videostab/stab/klt/pyramid.c b/src/modules/videostab/stab/klt/pyramid.c deleted file mode 100644 index 47077ce87..000000000 --- a/src/modules/videostab/stab/klt/pyramid.c +++ /dev/null @@ -1,139 +0,0 @@ -/********************************************************************* - * pyramid.c - * - *********************************************************************/ - -/* Standard includes */ -#include /* malloc() ? */ -#include /* memset() ? */ -#include /* */ - -/* Our includes */ -#include "base.h" -#include "error.h" -#include "convolve.h" /* for computing pyramid */ -#include "pyramid.h" - - -/********************************************************************* - * - */ - -_KLT_Pyramid _KLTCreatePyramid( - int ncols, - int nrows, - int subsampling, - int nlevels) -{ - _KLT_Pyramid pyramid; - int nbytes = sizeof(_KLT_PyramidRec) + - nlevels * sizeof(_KLT_FloatImage *) + - nlevels * sizeof(int) + - nlevels * sizeof(int); - int i; - - if (subsampling != 2 && subsampling != 4 && - subsampling != 8 && subsampling != 16 && subsampling != 32) - KLTError("(_KLTCreatePyramid) Pyramid's subsampling must " - "be either 2, 4, 8, 16, or 32"); - - - /* Allocate memory for structure and set parameters */ - pyramid = (_KLT_Pyramid)malloc(nbytes); - - /* Set parameters */ - pyramid->subsampling = subsampling; - pyramid->nLevels = nlevels; - pyramid->img = (_KLT_FloatImage *) (pyramid + 1); - pyramid->ncols = (int *) (pyramid->img + nlevels); - pyramid->nrows = (int *) (pyramid->ncols + nlevels); - - /* Allocate memory for each level of pyramid and assign pointers */ - for (i = 0 ; i < nlevels ; i++) { - pyramid->img[i] = _KLTCreateFloatImage(ncols, nrows); - pyramid->ncols[i] = ncols; - pyramid->nrows[i] = nrows; - ncols /= subsampling; - nrows /= subsampling; - } - - return pyramid; -} - - -/********************************************************************* - * - */ - -void _KLTFreePyramid( - _KLT_Pyramid pyramid) -{ - int i; - - /* Free images */ - for (i = 0 ; i < pyramid->nLevels ; i++) - _KLTFreeFloatImage(pyramid->img[i]); - - /* Free structure */ - free(pyramid); -} - - -/********************************************************************* - * - */ - -void _KLTComputePyramid( - _KLT_FloatImage img, - _KLT_Pyramid pyramid, - float sigma_fact) -{ - _KLT_FloatImage currimg, tmpimg; - int ncols = img->ncols, nrows = img->nrows; - int subsampling = pyramid->subsampling; - int subhalf = subsampling / 2; - float sigma = subsampling * sigma_fact; /* empirically determined */ - int oldncols; - int i, x, y; - - if (subsampling != 2 && subsampling != 4 && - subsampling != 8 && subsampling != 16 && subsampling != 32) - KLTError("(_KLTComputePyramid) Pyramid's subsampling must " - "be either 2, 4, 8, 16, or 32"); - - /* Copy original image to level 0 of pyramid */ - memcpy(pyramid->img[0]->data, img->data, ncols*nrows*sizeof(float)); - - currimg = img; - for (i = 1 ; i < pyramid->nLevels ; i++) { - tmpimg = _KLTCreateFloatImage(ncols, nrows); - _KLTComputeSmoothedImage(currimg, sigma, tmpimg); - - - /* Subsample */ - oldncols = ncols; - ncols /= subsampling; nrows /= subsampling; - for (y = 0 ; y < nrows ; y++) - for (x = 0 ; x < ncols ; x++) - pyramid->img[i]->data[y*ncols+x] = - tmpimg->data[(subsampling*y+subhalf)*oldncols + - (subsampling*x+subhalf)]; - - /* Reassign current image */ - currimg = pyramid->img[i]; - - _KLTFreeFloatImage(tmpimg); - } -} - - - - - - - - - - - - diff --git a/src/modules/videostab/stab/klt/pyramid.h b/src/modules/videostab/stab/klt/pyramid.h deleted file mode 100644 index eca9e6692..000000000 --- a/src/modules/videostab/stab/klt/pyramid.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************************* - * pyramid.h - *********************************************************************/ - -#ifndef _PYRAMID_H_ -#define _PYRAMID_H_ - -#include "klt_util.h" - -typedef struct { - int subsampling; - int nLevels; - _KLT_FloatImage *img; - int *ncols, *nrows; -} _KLT_PyramidRec, *_KLT_Pyramid; - - -_KLT_Pyramid _KLTCreatePyramid( - int ncols, - int nrows, - int subsampling, - int nlevels); - -void _KLTComputePyramid( - _KLT_FloatImage floatimg, - _KLT_Pyramid pyramid, - float sigma_fact); - -void _KLTFreePyramid( - _KLT_Pyramid pyramid); - -#endif diff --git a/src/modules/videostab/stab/klt/selectGoodFeatures.c b/src/modules/videostab/stab/klt/selectGoodFeatures.c deleted file mode 100644 index bb38a4c6c..000000000 --- a/src/modules/videostab/stab/klt/selectGoodFeatures.c +++ /dev/null @@ -1,430 +0,0 @@ -/********************************************************************* - * selectGoodFeatures.c - * - *********************************************************************/ - -/* Standard includes */ -#include /* malloc(), qsort() */ -#include /* fflush() */ -#include /* memset() */ -#include /* sqrt() */ - -/* Our includes */ -#include "base.h" -#include "error.h" -#include "convolve.h" -#include "klt.h" -#include "klt_util.h" -#include "pyramid.h" - -typedef enum {SELECTING_ALL, REPLACING_SOME} selectionMode; - -/*********************************************************************/ - -void _fillFeaturemap( - int x, int y, - uchar *featuremap, - int mindist, - int ncols, - int nrows) -{ - int ix, iy; - - for (iy = y - mindist ; iy <= y + mindist ; iy++) - for (ix = x - mindist ; ix <= x + mindist ; ix++) - if (ix >= 0 && ix < ncols && iy >= 0 && iy < nrows) - featuremap[iy*ncols+ix] = 1; -} - - -/********************************************************************* - * _enforceMinimumDistance - * - * Removes features that are within close proximity to better features. - * - * INPUTS - * featurelist: A list of features. The nFeatures property - * is used. - * - * OUTPUTS - * featurelist: Is overwritten. Nearby "redundant" features are removed. - * Writes -1's into the remaining elements. - * - * RETURNS - * The number of remaining features. - */ - -void _enforceMinimumDistance( - int *pointlist, /* featurepoints */ - int npoints, /* number of featurepoints */ - KLT_FeatureList featurelist, /* features */ - int ncols, int nrows, /* size of images */ - int mindist, /* min. dist b/w features */ - int min_eigenvalue, /* min. eigenvalue */ - KLT_BOOL overwriteAllFeatures) -{ - int indx; /* Index into features */ - int x, y, val; /* Location and trackability of pixel under consideration */ - uchar *featuremap; /* Boolean array recording proximity of features */ - int *ptr; - - /* Cannot add features with an eigenvalue less than one */ - if (min_eigenvalue < 1) min_eigenvalue = 1; - - /* Allocate memory for feature map and clear it */ - featuremap = (uchar *) malloc(ncols * nrows * sizeof(uchar)); - memset(featuremap, 0, ncols*nrows); - - /* Necessary because code below works with (mindist-1) */ - mindist--; - - /* If we are keeping all old good features, then add them to the featuremap */ - if (!overwriteAllFeatures) - for (indx = 0 ; indx < featurelist->nFeatures ; indx++) - if (featurelist->feature[indx]->val >= 0) { - x = (int) featurelist->feature[indx]->x; - y = (int) featurelist->feature[indx]->y; - _fillFeaturemap(x, y, featuremap, mindist, ncols, nrows); - } - - /* For each feature point, in descending order of importance, do ... */ - ptr = pointlist; - indx = 0; - while (1) { - - /* If we can't add all the points, then fill in the rest - of the featurelist with -1's */ - if (ptr >= pointlist + 3*npoints) { - while (indx < featurelist->nFeatures) { - if (overwriteAllFeatures || - featurelist->feature[indx]->val < 0) { - featurelist->feature[indx]->x = -1; - featurelist->feature[indx]->y = -1; - featurelist->feature[indx]->val = KLT_NOT_FOUND; - } - indx++; - } - break; - } - - x = *ptr++; - y = *ptr++; - val = *ptr++; - - while (!overwriteAllFeatures && - indx < featurelist->nFeatures && - featurelist->feature[indx]->val >= 0) - indx++; - - if (indx >= featurelist->nFeatures) break; - - /* If no neighbor has been selected, and if the minimum - eigenvalue is large enough, then add feature to the current list */ - if (!featuremap[y*ncols+x] && val >= min_eigenvalue) { - featurelist->feature[indx]->x = (KLT_locType) x; - featurelist->feature[indx]->y = (KLT_locType) y; - featurelist->feature[indx]->val = (int) val; - indx++; - - /* Fill in surrounding region of feature map, but - make sure that pixels are in-bounds */ - _fillFeaturemap(x, y, featuremap, mindist, ncols, nrows); - } - } - - /* Free feature map */ - free(featuremap); -} - - -/********************************************************************* - * _comparePoints - * - * Used by qsort (in _KLTSelectGoodFeatures) to determine - * which feature is better. - * By switching the '>' with the '<', qsort is fooled into sorting - * in descending order. - */ - -int _comparePoints(const void *a, const void *b) -{ - int v1 = *(((int *) a) + 2); - int v2 = *(((int *) b) + 2); - - if (v1 > v2) return(-1); - else if (v1 < v2) return(1); - else return(0); -} - -/********************************************************************* - * _sortPointList - */ - -void _sortPointList( - int *pointlist, - int npoints) -{ - qsort(pointlist, npoints, 3*sizeof(int), _comparePoints); -} - - -/********************************************************************* - * _minEigenvalue - * - * Given the three distinct elements of the symmetric 2x2 matrix - * [gxx gxy] - * [gxy gyy], - * Returns the minimum eigenvalue of the matrix. - */ - -float _minEigenvalue(float gxx, float gxy, float gyy) -{ - return (float) ((gxx + gyy - sqrt((gxx - gyy)*(gxx - gyy) + 4*gxy*gxy)) / 2.0); -} - - -/*********************************************************************/ - -void _KLTSelectGoodFeatures( - KLT_TrackingContext tc, - KLT_PixelType *img, - int ncols, - int nrows, - KLT_FeatureList featurelist, - selectionMode mode) -{ - _KLT_FloatImage floatimg, gradx, grady; - int window_hw, window_hh; - int *pointlist; - int npoints = 0; - KLT_BOOL overwriteAllFeatures = (mode == SELECTING_ALL) ? TRUE : FALSE; - KLT_BOOL floatimages_created = FALSE; - - /* Check window size (and correct if necessary) */ - if (tc->window_width % 2 != 1) { - tc->window_width = tc->window_width+1; - KLTWarning("Tracking context's window width must be odd. " - "Changing to %d.\n", tc->window_width); - } - if (tc->window_height % 2 != 1) { - tc->window_height = tc->window_height+1; - KLTWarning("Tracking context's window height must be odd. " - "Changing to %d.\n", tc->window_height); - } - if (tc->window_width < 3) { - tc->window_width = 3; - KLTWarning("Tracking context's window width must be at least three. \n" - "Changing to %d.\n", tc->window_width); - } - if (tc->window_height < 3) { - tc->window_height = 3; - KLTWarning("Tracking context's window height must be at least three. \n" - "Changing to %d.\n", tc->window_height); - } - window_hw = tc->window_width/2; - window_hh = tc->window_height/2; - - /* Create pointlist, which is a simplified version of a featurelist, */ - /* for speed. Contains only integer locations and values. */ - pointlist = (int *) malloc(ncols * nrows * 3 * sizeof(int)); - - /* Create temporary images, etc. */ - if (mode == REPLACING_SOME && tc->sequentialMode && tc->pyramid_last != NULL) { - - floatimg = ((_KLT_Pyramid) tc->pyramid_last)->img[0]; - gradx = ((_KLT_Pyramid) tc->pyramid_last_gradx)->img[0]; - grady = ((_KLT_Pyramid) tc->pyramid_last_grady)->img[0]; - - } else { - - floatimages_created = TRUE; - floatimg = _KLTCreateFloatImage(ncols, nrows); - gradx = _KLTCreateFloatImage(ncols, nrows); - grady = _KLTCreateFloatImage(ncols, nrows); - - if (tc->smoothBeforeSelecting) { - - _KLT_FloatImage tmpimg; - tmpimg = _KLTCreateFloatImage(ncols, nrows); - _KLTToFloatImage(img, ncols, nrows, tmpimg); - _KLTComputeSmoothedImage(tmpimg, _KLTComputeSmoothSigma(tc), floatimg); - _KLTFreeFloatImage(tmpimg); - - } else { - - _KLTToFloatImage(img, ncols, nrows, floatimg); - } - - /* Compute gradient of image in x and y direction */ - _KLTComputeGradients(floatimg, tc->grad_sigma, gradx, grady); - } - - /* Compute trackability of each image pixel as the minimum - of the two eigenvalues of the Z matrix */ - { - float gx, gy; - float gxx, gxy, gyy; - int xx, yy; - int *ptr; - float val; - unsigned int limit = 1; - int borderx = tc->borderx; /* Must not touch cols */ - int bordery = tc->bordery; /* lost by convolution */ - int x, y; - int i; - - if (borderx < window_hw) borderx = window_hw; - if (bordery < window_hh) bordery = window_hh; - - /* Find largest value of an int */ - for (i = 0 ; i < sizeof(int) ; i++) limit *= 256; - limit = limit/2 - 1; - - /* For most of the pixels in the image, do ... */ - ptr = pointlist; - for (y = bordery ; y < nrows - bordery ; y += tc->nSkippedPixels + 1) - for (x = borderx ; x < ncols - borderx ; x += tc->nSkippedPixels + 1) { - - /* Sum the gradients in the surrounding window */ - gxx = 0; gxy = 0; gyy = 0; - for (yy = y-window_hh ; yy <= y+window_hh ; yy++) - for (xx = x-window_hw ; xx <= x+window_hw ; xx++) { - gx = *(gradx->data + ncols*yy+xx); - gy = *(grady->data + ncols*yy+xx); - gxx += gx * gx; - gxy += gx * gy; - gyy += gy * gy; - } - - /* Store the trackability of the pixel as the minimum - of the two eigenvalues */ - *ptr++ = x; - *ptr++ = y; - val = _minEigenvalue(gxx, gxy, gyy); - if (val > limit) { - KLTWarning("(_KLTSelectGoodFeatures) minimum eigenvalue %f is " - "greater than the capacity of an int; setting " - "to maximum value", val); - val = (float) limit; - } - *ptr++ = (int) val; - npoints++; - } - } - - /* Sort the features */ - _sortPointList(pointlist, npoints); - - /* Check tc->mindist */ - if (tc->mindist < 0) { - KLTWarning("(_KLTSelectGoodFeatures) Tracking context field tc->mindist " - "is negative (%d); setting to zero", tc->mindist); - tc->mindist = 0; - } - - /* Enforce minimum distance between features */ - _enforceMinimumDistance( - pointlist, - npoints, - featurelist, - ncols, nrows, - tc->mindist, - tc->min_eigenvalue, - overwriteAllFeatures); - - /* Free memory */ - free(pointlist); - if (floatimages_created) { - _KLTFreeFloatImage(floatimg); - _KLTFreeFloatImage(gradx); - _KLTFreeFloatImage(grady); - } -} - - -/********************************************************************* - * KLTSelectGoodFeatures - * - * Main routine, visible to the outside. Finds the good features in - * an image. - * - * INPUTS - * tc: Contains parameters used in computation (size of image, - * size of window, min distance b/w features, sigma to compute - * image gradients, # of features desired). - * img: Pointer to the data of an image (probably unsigned chars). - * - * OUTPUTS - * features: List of features. The member nFeatures is computed. - */ - -void KLTSelectGoodFeatures( - KLT_TrackingContext tc, - KLT_PixelType *img, - int ncols, - int nrows, - KLT_FeatureList fl) -{ - if (tc->verbose >= 1) { - fprintf(stderr, "(KLT) Selecting the %d best features " - "from a %d by %d image... ", fl->nFeatures, ncols, nrows); - fflush(stderr); - } - - _KLTSelectGoodFeatures(tc, img, ncols, nrows, - fl, SELECTING_ALL); - - if (tc->verbose >= 1) - fprintf( - stderr, - "\n\t%d features found.\n", - KLTCountRemainingFeatures(fl) - ); -} - - -/********************************************************************* - * KLTReplaceLostFeatures - * - * Main routine, visible to the outside. Replaces the lost features - * in an image. - * - * INPUTS - * tc: Contains parameters used in computation (size of image, - * size of window, min distance b/w features, sigma to compute - * image gradients, # of features desired). - * img: Pointer to the data of an image (probably unsigned chars). - * - * OUTPUTS - * features: List of features. The member nFeatures is computed. - */ - -void KLTReplaceLostFeatures( - KLT_TrackingContext tc, - KLT_PixelType *img, - int ncols, - int nrows, - KLT_FeatureList fl) -{ - int nLostFeatures = fl->nFeatures - KLTCountRemainingFeatures(fl); - - if (tc->verbose >= 1) { - fprintf(stderr, "(KLT) Attempting to replace %d features " - "in a %d by %d image... ", nLostFeatures, ncols, nrows); - fflush(stderr); - } - - /* If there are any lost features, replace them */ - if (nLostFeatures > 0) - _KLTSelectGoodFeatures(tc, img, ncols, nrows, - fl, REPLACING_SOME); - - if (tc->verbose >= 1) - fprintf( - stderr, - "\n\t%d features replaced.\n", - nLostFeatures - fl->nFeatures + KLTCountRemainingFeatures(fl) - ); -} - - diff --git a/src/modules/videostab/stab/klt/trackFeatures.c b/src/modules/videostab/stab/klt/trackFeatures.c deleted file mode 100644 index 59acca151..000000000 --- a/src/modules/videostab/stab/klt/trackFeatures.c +++ /dev/null @@ -1,549 +0,0 @@ -/********************************************************************* - * trackFeatures.c - * - *********************************************************************/ - -/* Standard includes */ -#include /* fabs() */ -#include /* malloc() */ -#include /* fflush() */ - -/* Our includes */ -#include "base.h" -#include "error.h" -#include "convolve.h" /* for computing pyramid */ -#include "klt.h" -#include "klt_util.h" /* _KLT_FloatImage */ -#include "pyramid.h" /* _KLT_Pyramid */ - -typedef float *_FloatWindow; - -/********************************************************************* - * _interpolate - * - * Given a point (x,y) in an image, computes the bilinear interpolated - * gray-level value of the point in the image. - */ - -float _interpolate(float x, float y, _KLT_FloatImage img) { - - int xt = x; - int yt = y; - - float ax = x - xt; - float ay = y - yt; - - float *ptr = img->data + (img->ncols * yt) + xt; - - return ( - (1 - ax) * (1 - ay) * (*ptr) + - ax * (1 - ay) * (*(ptr + 1)) + - (1 - ax) * ay * (*(ptr + img->ncols)) + - ax * ay * (*(ptr + img->ncols + 1)) - ); -} - -/********************************************************************* - * _computeIntensityDifference - * - * Given two images and the window center in both images, - * aligns the images wrt the window and computes the difference - * between the two overlaid images. - */ - -void _computeIntensityDifference( - _KLT_FloatImage img1, /* images */ - _KLT_FloatImage img2, - float x1, float y1, /* center of window in 1st img */ - float x2, float y2, /* center of window in 2nd img */ - int width, int height, /* size of window */ - _FloatWindow imgdiff) /* output */ -{ - int hw = width/2, hh = height/2; - float g1, g2; - int i, j; - - /* Compute values */ - for (j = -hh ; j <= hh ; j++) - for (i = -hw ; i <= hw ; i++) { - g1 = _interpolate(x1+i, y1+j, img1); - g2 = _interpolate(x2+i, y2+j, img2); - *imgdiff++ = g1 - g2; - } -} - - -/********************************************************************* - * _computeGradientSum - * - * Given two gradients and the window center in both images, - * aligns the gradients wrt the window and computes the sum of the two - * overlaid gradients. - */ - -void _computeGradientSum( - _KLT_FloatImage gradx1, /* gradient images */ - _KLT_FloatImage grady1, - _KLT_FloatImage gradx2, - _KLT_FloatImage grady2, - float x1, float y1, /* center of window in 1st img */ - float x2, float y2, /* center of window in 2nd img */ - int width, int height, /* size of window */ - _FloatWindow gradx, /* output */ - _FloatWindow grady) /* " */ -{ - int hw = width/2, hh = height/2; - float g1, g2; - int i, j; - - /* Compute values */ - for (j = -hh ; j <= hh ; j++) - for (i = -hw ; i <= hw ; i++) { - g1 = _interpolate(x1+i, y1+j, gradx1); - g2 = _interpolate(x2+i, y2+j, gradx2); - *gradx++ = g1 + g2; - g1 = _interpolate(x1+i, y1+j, grady1); - g2 = _interpolate(x2+i, y2+j, grady2); - *grady++ = g1 + g2; - } -} - -/********************************************************************* - * _compute2by2GradientMatrix - * - */ - -void _compute2by2GradientMatrix( - _FloatWindow gradx, - _FloatWindow grady, - int width, /* size of window */ - int height, - float *gxx, /* return values */ - float *gxy, - float *gyy) - -{ - float gx, gy; - int i; - - /* Compute values */ - *gxx = 0.0; *gxy = 0.0; *gyy = 0.0; - for (i = 0 ; i < width * height ; i++) { - gx = *gradx++; - gy = *grady++; - *gxx += gx*gx; - *gxy += gx*gy; - *gyy += gy*gy; - } -} - - -/********************************************************************* - * _compute2by1ErrorVector - * - */ - -void _compute2by1ErrorVector( - _FloatWindow imgdiff, - _FloatWindow gradx, - _FloatWindow grady, - int width, /* size of window */ - int height, - float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid overshooting */ - float *ex, /* return values */ - float *ey) -{ - float diff; - int i; - - /* Compute values */ - *ex = 0; *ey = 0; - for (i = 0 ; i < width * height ; i++) { - diff = *imgdiff++; - *ex += diff * (*gradx++); - *ey += diff * (*grady++); - } - *ex *= step_factor; - *ey *= step_factor; -} - - -/********************************************************************* - * _solveEquation - * - * Solves the 2x2 matrix equation - * [gxx gxy] [dx] = [ex] - * [gxy gyy] [dy] = [ey] - * for dx and dy. - * - * Returns KLT_TRACKED on success and KLT_SMALL_DET on failure - */ - -int _solveEquation( - float gxx, float gxy, float gyy, - float ex, float ey, - float small, - float *dx, float *dy) -{ - float det = gxx*gyy - gxy*gxy; - - - if (det < small) return KLT_SMALL_DET; - - *dx = (gyy*ex - gxy*ey)/det; - *dy = (gxx*ey - gxy*ex)/det; - return KLT_TRACKED; -} - - -/********************************************************************* - * _allocateFloatWindow - */ - -_FloatWindow _allocateFloatWindow(int width, int height) { - - return (_FloatWindow)malloc(width * height * sizeof(float)); -} - -/********************************************************************* - * _sumAbsFloatWindow - */ - -float _sumAbsFloatWindow( - _FloatWindow fw, - int width, - int height) -{ - float sum = 0.0; - int w; - - for ( ; height > 0 ; height--) - for (w=0 ; w < width ; w++) - sum += (float) fabs(*fw++); - - return sum; -} - - -/********************************************************************* - * _trackFeature - * - * Tracks a feature point from one image to the next. - * - * RETURNS - * KLT_SMALL_DET if feature is lost, - * KLT_MAX_ITERATIONS if tracking stopped because iterations timed out, - * KLT_TRACKED otherwise. - */ - -int _trackFeature( - float x1, /* location of window in first image */ - float y1, - float *x2, /* starting location of search in second image */ - float *y2, - _KLT_FloatImage img1, - _KLT_FloatImage gradx1, - _KLT_FloatImage grady1, - _KLT_FloatImage img2, - _KLT_FloatImage gradx2, - _KLT_FloatImage grady2, - int width, /* size of window */ - int height, - float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid overshooting */ - int max_iterations, - float small, /* determinant threshold for declaring KLT_SMALL_DET */ - float th, /* displacement threshold for stopping */ - float max_residue) /* residue threshold for declaring KLT_LARGE_RESIDUE */ -{ - _FloatWindow imgdiff, gradx, grady; - float gxx, gxy, gyy, ex, ey, dx, dy; - int iteration = 0; - int status; - int hw = width / 2; - int hh = height / 2; - int nc = img1->ncols; - int nr = img1->nrows; - float one_plus_eps = 1.001f; /* To prevent rounding errors */ - - - /* Allocate memory for windows */ - imgdiff = _allocateFloatWindow(width, height); - gradx = _allocateFloatWindow(width, height); - grady = _allocateFloatWindow(width, height); - - /* Iteratively update the window position */ - do { - - /* If out of bounds, exit loop */ - if ( x1-hw < 0.0f || nc-( x1+hw) < one_plus_eps || - *x2-hw < 0.0f || nc-(*x2+hw) < one_plus_eps || - y1-hh < 0.0f || nr-( y1+hh) < one_plus_eps || - *y2-hh < 0.0f || nr-(*y2+hh) < one_plus_eps) { - status = KLT_OOB; - break; - } - - /* Compute gradient and difference windows */ - _computeIntensityDifference(img1, img2, x1, y1, *x2, *y2, - width, height, imgdiff); - _computeGradientSum(gradx1, grady1, gradx2, grady2, - x1, y1, *x2, *y2, width, height, gradx, grady); - - - /* Use these windows to construct matrices */ - _compute2by2GradientMatrix(gradx, grady, width, height, - &gxx, &gxy, &gyy); - _compute2by1ErrorVector(imgdiff, gradx, grady, width, height, step_factor, - &ex, &ey); - - /* Using matrices, solve equation for new displacement */ - status = _solveEquation(gxx, gxy, gyy, ex, ey, small, &dx, &dy); - if (status == KLT_SMALL_DET) break; - - *x2 += dx; - *y2 += dy; - iteration++; - - } while ((fabs(dx)>=th || fabs(dy)>=th) && iteration < max_iterations); - - /* Check whether window is out of bounds */ - if (*x2-hw < 0.0f || nc-(*x2+hw) < one_plus_eps || - *y2-hh < 0.0f || nr-(*y2+hh) < one_plus_eps) - status = KLT_OOB; - - /* Check whether residue is too large */ - if (status == KLT_TRACKED) { - - _computeIntensityDifference( - img1, img2, x1, y1, *x2, *y2, - width, height, imgdiff); - - if (_sumAbsFloatWindow(imgdiff, width, height)/(width*height) > max_residue) - status = KLT_LARGE_RESIDUE; - } - - /* Free memory */ - free(imgdiff); - free(gradx); - free(grady); - - /* Return appropriate value */ - if (status == KLT_SMALL_DET) - return KLT_SMALL_DET; - else if (status == KLT_OOB) - return KLT_OOB; - else if (status == KLT_LARGE_RESIDUE) - return KLT_LARGE_RESIDUE; - else if (iteration >= max_iterations) - return KLT_MAX_ITERATIONS; - else - return KLT_TRACKED; - -} - - -/*********************************************************************/ - -KLT_BOOL _outOfBounds( - float x, - float y, - int ncols, - int nrows, - int borderx, - int bordery) -{ - return (x < borderx || x > ncols-1-borderx || - y < bordery || y > nrows-1-bordery ); -} - -/********************************************************************* - * KLTTrackFeatures - * - * Tracks feature points from one image to the next. - */ - -void KLTTrackFeatures( - KLT_TrackingContext tc, - KLT_PixelType *img1, - KLT_PixelType *img2, - int ncols, - int nrows, - KLT_FeatureList featurelist) -{ - _KLT_FloatImage tmpimg = NULL; - _KLT_FloatImage floatimg1 = NULL; - _KLT_FloatImage floatimg2 = NULL; - - _KLT_Pyramid pyramid1, pyramid1_gradx, pyramid1_grady; - _KLT_Pyramid pyramid2, pyramid2_gradx, pyramid2_grady; - - int val = 0; - KLT_BOOL floatimg1_created = FALSE; - - float subsampling = (float)tc->subsampling; - float xloc, yloc, xlocout, ylocout; - int i, indx, r; - - if (tc->verbose >= 1) { - fprintf(stderr, "(KLT) Tracking %d features in a %d by %d image... ", - KLTCountRemainingFeatures(featurelist), ncols, nrows); - fflush(stderr); - } - - /* Check window size (and correct if necessary) */ - if (tc->window_width % 2 != 1) { - tc->window_width = tc->window_width+1; - KLTWarning("Tracking context's window width must be odd. " - "Changing to %d.\n", tc->window_width); - } - if (tc->window_height % 2 != 1) { - tc->window_height = tc->window_height+1; - KLTWarning("Tracking context's window height must be odd. " - "Changing to %d.\n", tc->window_height); - } - if (tc->window_width < 3) { - tc->window_width = 3; - KLTWarning("Tracking context's window width must be at least three. \n" - "Changing to %d.\n", tc->window_width); - } - if (tc->window_height < 3) { - tc->window_height = 3; - KLTWarning("Tracking context's window height must be at least three. \n" - "Changing to %d.\n", tc->window_height); - } - - /* Create temporary image */ - tmpimg = _KLTCreateFloatImage(ncols, nrows); - - /* Process first image by converting to float, smoothing, computing */ - /* pyramid, and computing gradient pyramids */ - if (tc->sequentialMode && tc->pyramid_last != NULL) { - pyramid1 = (_KLT_Pyramid) tc->pyramid_last; - pyramid1_gradx = (_KLT_Pyramid) tc->pyramid_last_gradx; - pyramid1_grady = (_KLT_Pyramid) tc->pyramid_last_grady; - if (pyramid1->ncols[0] != ncols || pyramid1->nrows[0] != nrows) - KLTError("(KLTTrackFeatures) Size of incoming image (%d by %d) " - "is different from size of previous image (%d by %d)\n", - ncols, nrows, pyramid1->ncols[0], pyramid1->nrows[0]); - } else { - floatimg1_created = TRUE; - floatimg1 = _KLTCreateFloatImage(ncols, nrows); - _KLTToFloatImage(img1, ncols, nrows, tmpimg); - _KLTComputeSmoothedImage(tmpimg, _KLTComputeSmoothSigma(tc), floatimg1); - pyramid1 = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); - _KLTComputePyramid(floatimg1, pyramid1, tc->pyramid_sigma_fact); - pyramid1_gradx = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); - pyramid1_grady = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); - for (i = 0 ; i < tc->nPyramidLevels ; i++) - _KLTComputeGradients(pyramid1->img[i], tc->grad_sigma, - pyramid1_gradx->img[i], - pyramid1_grady->img[i]); - } - - /* Do the same thing with second image */ - floatimg2 = _KLTCreateFloatImage(ncols, nrows); - _KLTToFloatImage(img2, ncols, nrows, tmpimg); - _KLTComputeSmoothedImage(tmpimg, _KLTComputeSmoothSigma(tc), floatimg2); - pyramid2 = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); - _KLTComputePyramid(floatimg2, pyramid2, tc->pyramid_sigma_fact); - pyramid2_gradx = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); - pyramid2_grady = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); - for (i = 0 ; i < tc->nPyramidLevels ; i++) - _KLTComputeGradients(pyramid2->img[i], tc->grad_sigma, - pyramid2_gradx->img[i], - pyramid2_grady->img[i]); - - /* For each feature, do ... */ - for (indx = 0 ; indx < featurelist->nFeatures ; indx++) { - - /* Only track features that are not lost */ - if (featurelist->feature[indx]->val >= 0) { - - xloc = featurelist->feature[indx]->x; - yloc = featurelist->feature[indx]->y; - - /* Transform location to coarsest resolution */ - for (r = tc->nPyramidLevels - 1 ; r >= 0 ; r--) { - xloc /= subsampling; yloc /= subsampling; - } - xlocout = xloc; ylocout = yloc; - - /* Beginning with coarsest resolution, do ... */ - for (r = tc->nPyramidLevels - 1 ; r >= 0 ; r--) { - - /* Track feature at current resolution */ - xloc *= subsampling; yloc *= subsampling; - xlocout *= subsampling; ylocout *= subsampling; - - val = _trackFeature(xloc, yloc, - &xlocout, &ylocout, - pyramid1->img[r], - pyramid1_gradx->img[r], pyramid1_grady->img[r], - pyramid2->img[r], - pyramid2_gradx->img[r], pyramid2_grady->img[r], - tc->window_width, tc->window_height, - tc->step_factor, - tc->max_iterations, - tc->min_determinant, - tc->min_displacement, - tc->max_residue); - - if (val==KLT_SMALL_DET || val==KLT_OOB) - break; - } - - /* Record feature */ - if (val == KLT_OOB) { - featurelist->feature[indx]->x = -1.0; - featurelist->feature[indx]->y = -1.0; - featurelist->feature[indx]->val = KLT_OOB; - } else if (_outOfBounds(xlocout, ylocout, ncols, nrows, tc->borderx, tc->bordery)) { - featurelist->feature[indx]->x = -1.0; - featurelist->feature[indx]->y = -1.0; - featurelist->feature[indx]->val = KLT_OOB; - } else if (val == KLT_SMALL_DET) { - featurelist->feature[indx]->x = -1.0; - featurelist->feature[indx]->y = -1.0; - featurelist->feature[indx]->val = KLT_SMALL_DET; - } else if (val == KLT_LARGE_RESIDUE) { - featurelist->feature[indx]->x = -1.0; - featurelist->feature[indx]->y = -1.0; - featurelist->feature[indx]->val = KLT_LARGE_RESIDUE; - } else if (val == KLT_MAX_ITERATIONS) { - featurelist->feature[indx]->x = -1.0; - featurelist->feature[indx]->y = -1.0; - featurelist->feature[indx]->val = KLT_MAX_ITERATIONS; - } else { - featurelist->feature[indx]->x = xlocout; - featurelist->feature[indx]->y = ylocout; - featurelist->feature[indx]->val = KLT_TRACKED; - } - } - } - - if (tc->sequentialMode) { - tc->pyramid_last = pyramid2; - tc->pyramid_last_gradx = pyramid2_gradx; - tc->pyramid_last_grady = pyramid2_grady; - } else { - _KLTFreePyramid(pyramid2); - _KLTFreePyramid(pyramid2_gradx); - _KLTFreePyramid(pyramid2_grady); - } - - /* Free memory */ - _KLTFreeFloatImage(tmpimg); - if (floatimg1_created) _KLTFreeFloatImage(floatimg1); - _KLTFreeFloatImage(floatimg2); - _KLTFreePyramid(pyramid1); - _KLTFreePyramid(pyramid1_gradx); - _KLTFreePyramid(pyramid1_grady); - - if (tc->verbose >= 1) - fprintf( - stderr, - "\n\t%d features successfully tracked.\n", - KLTCountRemainingFeatures(featurelist) - ); -} - diff --git a/src/modules/videostab/stab/main.c b/src/modules/videostab/stab/main.c deleted file mode 100644 index 24b5c2ebf..000000000 --- a/src/modules/videostab/stab/main.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Video stabilizer - * - * Copyright (c) 2008 Lenny - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -//#include - -#include "avi/avi.h" - -#include "vector.h" -#include "utils.h" -#include "estimate.h" -#include "resample.h" - -AviMovie mv_in, mv_out; - -void print_help(char *argv[]) { - - printf( - " \n" - "Video stabilizer \n" - " \n" - "Usage: \n" - " %s [options] \n" - " \n" - "Options: \n" - " -r # | Rolling shutter angle | default: 0 | range: 0 - 180 \n" - " -q # | Output MJPEG quality | default: 100 | range: 50 - 100 \n" - " \n", - argv[0] - ); - - exit(EXIT_FAILURE); -} - -int main(int argc, char *argv[]) { - - int opt_shutter_angle = 0; - int opt_mjpeg_quality = 100; - - int nf, i, nc, nr; - int tfs, fps; - - vc *pos_i, *pos_h, *pos_y; - - es_ctx *es; - rs_ctx *rs; - - opterr = 0; - - while ((i = getopt(argc, argv, "r:q:")) != -1) { - - switch (i) { - - case 'r': - opt_shutter_angle = atoi(optarg); - break; - - case 'q': - opt_mjpeg_quality = atoi(optarg); - break; - - default: - print_help(argv); - } - } - - if (argc < optind + 2) - print_help(argv); - - if (AVI_open_movie(argv[optind], &mv_in) != AVI_ERROR_NONE) { - - printf("error: can't read from %s\n", argv[optind]); - return EXIT_FAILURE; - } - - if (mv_in.header->Streams < 1 || mv_in.streams[0].sh.Type != AVIST_VIDEO) { - - printf("error: video stream not found on %s\n", argv[optind]); - return EXIT_FAILURE; - } - - if (AVI_open_compress(argv[optind + 1], &mv_out, 1, AVI_FORMAT_MJPEG) != AVI_ERROR_NONE) { - - printf("error: can't write to %s\n", argv[optind + 1]); - return EXIT_FAILURE; - } - - printf("status: setup\n"); - - prepare_lanc_kernels(); - - nc = mv_in.header->Width; - nr = mv_in.header->Height; - - tfs = mv_in.header->TotalFrames; - fps = 1000000 / mv_in.header->MicroSecPerFrame; - - pos_i = (vc *)malloc(tfs * sizeof(vc)); - pos_h = (vc *)malloc(tfs * sizeof(vc)); - - pos_y = (vc *)malloc(nr * sizeof(vc)); - - AVI_set_compress_option(&mv_out, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_WIDTH, &nc); - AVI_set_compress_option(&mv_out, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_HEIGHT, &nr); - AVI_set_compress_option(&mv_out, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_FRAMERATE, &fps); - AVI_set_compress_option(&mv_out, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_QUALITY, &opt_mjpeg_quality); - - es = es_init(nc, nr); - rs = rs_init(nc, nr); - - printf("status: estimating\n"); - - for (nf = 0; nf < tfs; nf ++) { - - unsigned char *fr = (unsigned char *)AVI_read_frame(&mv_in, AVI_FORMAT_RGB24, nf, 0); - - pos_i[nf] = vc_add( - nf > 0 ? pos_i[nf - 1] : vc_set(0.0, 0.0), - es_estimate(es, fr) - ); - - free(fr); - - if ((nf + 1) % 10 == 0) { - - printf("."); - fflush(stdout); - } - } - - printf("\nstatus: filtering\n"); - - hipass(pos_i, pos_h, tfs, fps / 2); - - printf("status: resampling\n"); - - for (nf = 0; nf < tfs; nf ++) { - - unsigned char *fr = (unsigned char *)AVI_read_frame(&mv_in, AVI_FORMAT_RGB24, nf, 0); - - for (i = 0; i < nr; i ++) { - - pos_y[i] = interp( - pos_h, tfs, - nf + (i - nr / 2.0) * opt_shutter_angle / (nr * 360.0) - ); - } - - rs_resample(rs, fr, pos_y); - - AVI_write_frame(&mv_out, nf, AVI_FORMAT_RGB24, fr, nc * nr * 3 * sizeof(unsigned char)); - - if ((nf + 1) % 10 == 0) { - - printf("."); - fflush(stdout); - } - } - - printf("\nstatus: closing\n"); - - es_free(es); - rs_free(rs); - - free_lanc_kernels(); - - AVI_close(&mv_in); - AVI_close_compress(&mv_out); - - return EXIT_SUCCESS; -} - diff --git a/src/modules/videostab/stab/resample.c b/src/modules/videostab/stab/resample.c deleted file mode 100644 index 12d82af70..000000000 --- a/src/modules/videostab/stab/resample.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Video stabilizer - * - * Copyright (c) 2008 Lenny - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include - -#include "resample.h" -#include "utils.h" - -rs_ctx *rs_init(int nc, int nr) { - - rs_ctx *rs = (rs_ctx *)malloc(sizeof(rs_ctx)); - - rs->tf = (unsigned char *)malloc(nc * nr * 3 * sizeof(unsigned char)); - - rs->nc = nc; - rs->nr = nr; - - return rs; -} - -void rs_resample(int* lanc_kernels,rs_ctx *rs, unsigned char *f, vc *p) { - - int i, x, y, c; - - for (y = 0; y < rs->nr; y ++) { - - int yp = y * rs->nc; - int xd = floor(p[y].x); - - int *lk = select_lanc_kernel(lanc_kernels,p[y].x); - - for (x = 0; x < rs->nc; x ++) { - - int pd = (yp + x) * 3; - int a[3]; - - for (c = 0; c < 3; c ++) - a[c] = 0; - - for (i = -3; i < 5; i ++) { - - int ps = (yp + clamp(x + xd + i, 0, rs->nc - 1)) * 3; - - for (c = 0; c < 3; c ++) - a[c] += f[ps + c] * lk[i + 3]; - } - - for (c = 0; c < 3; c ++) - rs->tf[pd + c] = clamp(a[c] / 1024, 0, 255); - } - } - - for (y = 0; y < rs->nr; y ++) { - - int yp = y * rs->nc; - int yd = floor(p[y].y); - - int *lk = select_lanc_kernel(lanc_kernels,p[y].y); - - for (x = 0; x < rs->nc; x ++) { - - int pd = (yp + x) * 3; - int a[3]; - - for (c = 0; c < 3; c ++) - a[c] = 0; - - for (i = -3; i < 5; i ++) { - - int ps = (clamp(y + yd + i, 0, rs->nr - 1) * rs->nc + x) * 3; - - for (c = 0; c < 3; c ++) - a[c] += rs->tf[ps + c] * lk[i + 3]; - } - - for (c = 0; c < 3; c ++) - f[pd + c] = clamp(a[c] / 1024, 0, 255); - } - } -} - -void rs_free(rs_ctx *rs) { - - free(rs->tf); - - free(rs); -} - diff --git a/src/modules/videostab/stab/resample.h b/src/modules/videostab/stab/resample.h deleted file mode 100644 index aefa4a806..000000000 --- a/src/modules/videostab/stab/resample.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef RESAMPLE_H -#define RESAMPLE_H - -#include "vector.h" - -typedef struct { - - unsigned char *tf; - int nc, nr; - -} rs_ctx; - -rs_ctx *rs_init(int, int); - -void rs_resample(int*,rs_ctx *, unsigned char *, vc *); - -void rs_free(rs_ctx *); - -#endif - diff --git a/src/modules/videostab/stab/utils.c b/src/modules/videostab/stab/utils.c deleted file mode 100644 index 43fc30efd..000000000 --- a/src/modules/videostab/stab/utils.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Video stabilizer - * - * Copyright (c) 2008 Lenny - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include - -#include "utils.h" - -float lanc(float x, float r) { - - float t = x * M_PI; - - if (x == 0.0) - return 1.0; - - if (x <= -r || x >= r) - return 0.0; - - return r * sin(t) * sin(t / r) / (t * t); -} - -float hann(float x, float d) { - - if (x < 0.0 || x > d) - return 0.0; - - return 0.5 * (1.0 - cos((M_PI * 2.0 * x) / (d - 1.0))); -} - -int clamp(int a, int b, int c) { - - if (a < b) - a = b; - - if (a > c) - a = c; - - return a; -} - -void lopass(vc *vi, vc *vo, int l, int r) { - - int d = r * 2 + 1; - float *ck = (float *)malloc(d * sizeof(float)); - float cw = 0.0; - - int i, j; - - for (i = 0; i < d; i ++) - cw += ck[i] = hann(i, d - 1); - - for (i = 0; i < l; i ++) { - - vc a = vc_zero(); - - for (j = i - r; j <= i + r; j ++) { - - int jc = clamp(j, 0, l - 1); - - vc_mul_acc(&a, vi[jc], ck[j - i + r]); - } - - vo[i] = vc_div(a, cw); - } - - free(ck); -} - -void hipass(vc *vi, vc *vo, int l, int r) { - - int i; - - lopass(vi, vo, l, r); - - for (i = 0; i < l; i ++) - vo[i] = vc_sub(vi[i], vo[i]); -} - -int* prepare_lanc_kernels() { - - int i, j; - - int* lanc_kernels = (int *)malloc(256 * 8 * sizeof(int)); - - for (i = 0; i < 256; i ++) - for (j = -3; j < 5; j ++) - lanc_kernels[i * 8 + j + 3] = lanc(j - i / 256.0, 4) * 1024.0; - return lanc_kernels; -} - -int *select_lanc_kernel(int* lanc_kernels,float x) { - - return lanc_kernels + (int)((x - floor(x)) * 256.0) * 8; -} - -void free_lanc_kernels(int *lanc_kernels) { - - free(lanc_kernels); -} - -vc interp(int* lanc_kernels, vc *vi, int l, float x) { - - vc a = vc_zero(); - int xd = floor(x); - int *lk = select_lanc_kernel(lanc_kernels,x); - - int i; - - for (i = -3; i < 5; i ++) { - - int ic = clamp(xd + i, 0, l - 1); - - vc_mul_acc(&a, vi[ic], lk[i + 3]); - } - - return vc_div(a, 1024.0); -} - diff --git a/src/modules/videostab/stab/utils.h b/src/modules/videostab/stab/utils.h deleted file mode 100644 index a8c388626..000000000 --- a/src/modules/videostab/stab/utils.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H - -#include "vector.h" - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - - -float lanc(float, float); -float hann(float, float); - -int clamp(int, int, int); - -void lopass(vc *, vc *, int, int); -void hipass(vc *, vc *, int, int); - -int* prepare_lanc_kernels(); -int *select_lanc_kernel(int*,float); -void free_lanc_kernels(int*); - -vc interp(int*,vc *, int, float); - -#endif - diff --git a/src/modules/videostab/stab/vector.c b/src/modules/videostab/stab/vector.c deleted file mode 100644 index 9c14d3654..000000000 --- a/src/modules/videostab/stab/vector.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Video stabilizer - * - * Copyright (c) 2008 Lenny - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include - -#include "vector.h" - -vc vc_zero() { - - vc v3; - - v3.x = 0.0; - v3.y = 0.0; - - return v3; -} - -vc vc_one() { - - vc v3; - - v3.x = 1.0; - v3.y = 1.0; - - return v3; -} - -vc vc_set(float x, float y) { - - vc v3; - - v3.x = x; - v3.y = y; - - return v3; -} - -vc vc_add(vc v1, vc v2) { - - vc v3; - - v3.x = v1.x + v2.x; - v3.y = v1.y + v2.y; - - return v3; -} - -vc vc_sub(vc v1, vc v2) { - - vc v3; - - v3.x = v1.x - v2.x; - v3.y = v1.y - v2.y; - - return v3; -} - -vc vc_mul(vc v1, float v2) { - - vc v3; - - v3.x = v1.x * v2; - v3.y = v1.y * v2; - - return v3; -} - -vc vc_div(vc v1, float v2) { - - vc v3; - - v3.x = v1.x / v2; - v3.y = v1.y / v2; - - return v3; -} - -void vc_acc(vc *v1, vc v2) { - - v1->x += v2.x; - v1->y += v2.y; -} - -void vc_mul_acc(vc *v1, vc v2, float v3) { - - v1->x += v2.x * v3; - v1->y += v2.y * v3; -} - -float vc_len(vc v) { - - return sqrt(v.x * v.x + v.y * v.y); -} - -float vc_ang(vc v1, vc v2) { - - float c = v1.x * v2.y - v1.y * v2.x; - - if (fabs(c) > 0.0) { - - float l = vc_len(v1) * vc_len(v2); - float d = acos((v1.x * v2.x + v1.y * v2.y) / l); - - if (c > 0.0) - return d; - else - return -d; - } - - return 0.0; -} - diff --git a/src/modules/videostab/stab/vector.h b/src/modules/videostab/stab/vector.h deleted file mode 100644 index 0a773f0a5..000000000 --- a/src/modules/videostab/stab/vector.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef VECTOR_H -#define VECTOR_H - -typedef struct { - - float x, y; - -} vc; - -vc vc_zero(); -vc vc_one(); -vc vc_set(float, float); - -vc vc_add(vc, vc); -vc vc_sub(vc, vc); - -vc vc_mul(vc, float); -vc vc_div(vc, float); - -void vc_acc(vc *, vc); -void vc_mul_acc(vc *, vc, float); - -float vc_len(vc); -float vc_ang(vc, vc); - -#endif - diff --git a/src/modules/videostab/stabilize.c b/src/modules/videostab/stabilize.c deleted file mode 100644 index 00b4017a4..000000000 --- a/src/modules/videostab/stabilize.c +++ /dev/null @@ -1,954 +0,0 @@ -/* - * filter_stabilize.c - * - * Copyright (C) Georg Martius - June 2007 - * georg dot martius at web dot de - * mlt adaption by Marco Gittler marco at gitma dot de 2011 - * - * This file is part of transcode, a video stream processing tool - * - * transcode is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * transcode is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -/* Typical call: - * transcode -V -J stabilize=shakiness=5:show=1,preview - * -i inp.mpeg -y null,null -o dummy - * all parameters are optional -*/ - -#define MOD_NAME "filter_stabilize.so" -#define MOD_VERSION "v0.75 (2010-04-07)" -#define MOD_CAP "extracts relative transformations of \n\ - subsequent frames (used for stabilization together with the\n\ - transform filter in a second pass)" -#define MOD_AUTHOR "Georg Martius" - -/* Ideas: - - Try OpenCL/Cuda, this should work great - - use smoothing on the frames and then use gradient decent! - - stepsize could be adapted (maybe to check only one field with large - stepsize and use the maximally required for the other fields -*/ - -#define MOD_FEATURES \ - TC_MODULE_FEATURE_FILTER|TC_MODULE_FEATURE_VIDEO -#define MOD_FLAGS \ - TC_MODULE_FLAG_RECONFIGURABLE | TC_MODULE_FLAG_DELAY -#define MAX(a,b) ((a < b) ? (b) : (a)) -#define MIN(a,b) ((a < b) ? (a) : (b)) -#include "stabilize.h" -#include -#include -#include -#include -#ifdef USE_SSE2 -#include -#endif - -void addTrans(StabData* sd, Transform sl) -{ - if (!sd->transs) { - sd->transs = tlist_new(0); - } - tlist_append(sd->transs, &sl,sizeof(Transform) ); -} - - - -/** initialise measurement fields on the frame. - The size of the fields and the maxshift is used to - calculate an optimal distribution in the frame. -*/ -int initFields(StabData* sd) -{ - int size = sd->field_size; - int rows = MAX(3,(sd->height - sd->maxshift*2)/size-1); - int cols = MAX(3,(sd->width - sd->maxshift*2)/size-1); - // make sure that the remaining rows have the same length - sd->field_num = rows*cols; - sd->field_rows = rows; - mlt_log_debug (NULL,"field setup: rows: %i cols: %i Total: %i fields", - rows, cols, sd->field_num); - - if (!(sd->fields = malloc(sizeof(Field) * sd->field_num))) { - mlt_log_error ( NULL, "malloc failed!\n"); - return 0; - } else { - int i, j; - // the border is the amount by which the field centers - // have to be away from the image boundary - // (stepsize is added in case shift is increased through stepsize) - int border = size/2 + sd->maxshift + sd->stepsize; - int step_x = (sd->width - 2*border)/MAX(cols-1,1); - int step_y = (sd->height - 2*border) / MAX(rows-1,1); - for (j = 0; j < rows; j++) { - for (i = 0; i < cols; i++) { - int idx = j*cols+i; - sd->fields[idx].x = border + i*step_x; - sd->fields[idx].y = border + j*step_y; - sd->fields[idx].size = size; - } - } - } - return 1; -} - - -/** - compares the two given images and returns the average absolute difference - \param d_x shift in x direction - \param d_y shift in y direction -*/ -double compareImg(unsigned char* I1, unsigned char* I2, - int width, int height, int bytesPerPixel, int d_x, int d_y) -{ - int i, j; - unsigned char* p1 = NULL; - unsigned char* p2 = NULL; - long int sum = 0; - int effectWidth = width - abs(d_x); - int effectHeight = height - abs(d_y); - -/* DEBUGGING code to export single frames */ -/* char buffer[100]; */ -/* sprintf(buffer, "pic_%02ix%02i_1.ppm", d_x, d_y); */ -/* FILE *pic1 = fopen(buffer, "w"); */ -/* sprintf(buffer, "pic_%02ix%02i_2.ppm", d_x, d_y); */ -/* FILE *pic2 = fopen(buffer, "w"); */ -/* fprintf(pic1, "P6\n%i %i\n255\n", effectWidth, effectHeight); */ -/* fprintf(pic2, "P6\n%i %i\n255\n", effectWidth, effectHeight); */ - - for (i = 0; i < effectHeight; i++) { - p1 = I1; - p2 = I2; - if (d_y > 0 ){ - p1 += (i + d_y) * width * bytesPerPixel; - p2 += i * width * bytesPerPixel; - } else { - p1 += i * width * bytesPerPixel; - p2 += (i - d_y) * width * bytesPerPixel; - } - if (d_x > 0) { - p1 += d_x * bytesPerPixel; - } else { - p2 -= d_x * bytesPerPixel; - } -#ifdef USE_SSE2 - __m128i A,B,C,D,E; - for (j = 0; j < effectWidth * bytesPerPixel - 16; j++) { -#else - for (j = 0; j < effectWidth * bytesPerPixel; j++) { -#endif - /* fwrite(p1,1,1,pic1);fwrite(p1,1,1,pic1);fwrite(p1,1,1,pic1); - fwrite(p2,1,1,pic2);fwrite(p2,1,1,pic2);fwrite(p2,1,1,pic2); - */ -#ifdef USE_SSE2 - A= _mm_loadu_si128((__m128i*)p1); //load unaligned data - B= _mm_loadu_si128((__m128i*)p2); - C= _mm_sad_epu8(A, B);//diff per 8 bit pixel stored in 2 64 byte values - D = _mm_srli_si128(C, 8); // shift first 64 byte value to align at the same as C - E = _mm_add_epi32(C, D); // add the 2 values (sum of all diffs) - sum+= _mm_cvtsi128_si32(E); //convert _m128i to int - - p1+=16; - p2+=16; - j+=15; -#else - sum += abs((int)*p1 - (int)*p2); - p1++; - p2++; -#endif - } - } - /* fclose(pic1); - fclose(pic2); - */ - return sum/((double) effectWidth * effectHeight * bytesPerPixel); -} - -/** - compares a small part of two given images - and returns the average absolute difference. - Field center, size and shift have to be chosen, - so that no clipping is required - - \param field Field specifies position(center) and size of subimage - \param d_x shift in x direction - \param d_y shift in y direction -*/ -double compareSubImg(unsigned char* const I1, unsigned char* const I2, - const Field* field, - int width, int height, int bytesPerPixel, int d_x, int d_y) -{ - int k, j; - unsigned char* p1 = NULL; - unsigned char* p2 = NULL; - int s2 = field->size / 2; - double sum=0.0; - - p1=I1 + ((field->x - s2) + (field->y - s2)*width)*bytesPerPixel; - - p2=I2 + ((field->x - s2 + d_x) + (field->y - s2 + d_y)*width)*bytesPerPixel; - // TODO: use some mmx or sse stuff here -#ifdef USE_SSE2 - __m128i A,B,C,D,E; -#endif - for (j = 0; j < field->size; j++){ -#ifdef USE_SSE2 - for (k = 0; k < (field->size * bytesPerPixel) - 16 ; k++) { - A= _mm_loadu_si128((__m128i*)p1); //load unaligned data - B= _mm_loadu_si128((__m128i*)p2); - C= _mm_sad_epu8(A, B);//abd diff stored in 2 64 byte values - D = _mm_srli_si128(C, 8); // shift value 8 byte right - E = _mm_add_epi32(C, D); // add the 2 values (sum of all diffs) - sum+= _mm_cvtsi128_si32(E); //convert _m128i to int - - p1+=16; - p2+=16; - k+=15; -#else - for (k = 0; k < (field->size * bytesPerPixel); k++) { - sum += abs((int)*p1 - (int)*p2); - p1++; - p2++; -#endif - } - p1 += ((width - field->size) * bytesPerPixel); - p2 += ((width - field->size) * bytesPerPixel); - } - return sum/((double) field->size *field->size* bytesPerPixel); -} - -/** \see contrastSubImg called with bytesPerPixel=1*/ -double contrastSubImgYUV(StabData* sd, const Field* field){ - return contrastSubImg(sd->curr,field,sd->width,sd->height,1); -} - -/** - \see contrastSubImg three times called with bytesPerPixel=3 - for all channels - */ -double contrastSubImgRGB(StabData* sd, const Field* field){ - unsigned char* const I = sd->curr; - return ( contrastSubImg(I, field,sd->width,sd->height,3) - + contrastSubImg(I+1,field,sd->width,sd->height,3) - + contrastSubImg(I+2,field,sd->width,sd->height,3))/3; -} - -/** - calculates Michelson-contrast in the given small part of the given image - - \param I pointer to framebuffer - \param field Field specifies position(center) and size of subimage - \param width width of frame - \param height height of frame - \param bytesPerPixel calc contrast for only for first channel -*/ -double contrastSubImg(unsigned char* const I, const Field* field, - int width, int height, int bytesPerPixel) -{ -#if USE_SSE2 - int k, j; - int s2 = field->size / 2; - __m128i mini = _mm_set_epi64(_mm_set1_pi8(255), _mm_set1_pi8(255)); - __m128i maxi = _mm_set_epi64(_mm_set1_pi8(0) , _mm_set1_pi8(0)); - unsigned char* p = I + ((field->x - s2) + (field->y - s2)*width)*bytesPerPixel; - __m128i A; - for (j = 0; j < field->size; j++){ - for (k = 0; k < (field->size * bytesPerPixel)-16 ; k++) { - A= _mm_loadu_si128((__m128i*)p); //load unaligned data - - maxi = _mm_max_epu8(A,maxi); - mini = _mm_min_epu8(A,mini); - p+=16; - k+=15; - } - p += (width - field->size) * bytesPerPixel; - } - int max=0; - union { - __m128i m; - uint8_t t[16]; - } m; - m.m=maxi; - for (j=0;j<16;j++) { - if (m.t[j] >max) - max=m.t[j]; - } - int min=255; - m.m=mini; - for (j=0;j<16;j++) { - if (m.t[j] size / 2; - unsigned char mini = 255; - unsigned char maxi = 0; - p = I + ((field->x - s2) + (field->y - s2)*width)*bytesPerPixel; - // TODO: use some mmx or sse stuff here - - for (j = 0; j < field->size; j++){ - for (k = 0; k < field->size * bytesPerPixel; k++) { - mini = (mini < *p) ? mini : *p; - maxi = (maxi > *p) ? maxi : *p; - p += bytesPerPixel; - } - p += (width - field->size) * bytesPerPixel; - } - return (maxi-mini)/(maxi+mini+0.1); // +0.1 to avoid division by 0 -#endif -} - -/** tries to register current frame onto previous frame. - This is the most simple algorithm: - shift images to all possible positions and calc summed error - Shift with minimal error is selected. -*/ -Transform calcShiftRGBSimple(StabData* sd) -{ - int x = 0, y = 0; - int i, j; - double minerror = 1e20; - for (i = -sd->maxshift; i <= sd->maxshift; i++) { - for (j = -sd->maxshift; j <= sd->maxshift; j++) { - double error = compareImg(sd->curr, sd->prev, - sd->width, sd->height, 3, i, j); - if (error < minerror) { - minerror = error; - x = i; - y = j; - } - } - } - return new_transform(x, y, 0, 0, 0); -} - - -/** tries to register current frame onto previous frame. - (only the luminance is used) - This is the most simple algorithm: - shift images to all possible positions and calc summed error - Shift with minimal error is selected. -*/ -Transform calcShiftYUVSimple(StabData* sd) -{ - int x = 0, y = 0; - int i, j; - unsigned char *Y_c, *Y_p;// , *Cb, *Cr; -#ifdef STABVERBOSE - FILE *f = NULL; - char buffer[32]; - tc_snprintf(buffer, sizeof(buffer), "f%04i.dat", sd->t); - f = fopen(buffer, "w"); - fprintf(f, "# splot \"%s\"\n", buffer); -#endif - - // we only use the luminance part of the image - Y_c = sd->curr; - // Cb_c = sd->curr + sd->width*sd->height; - //Cr_c = sd->curr + 5*sd->width*sd->height/4; - Y_p = sd->prev; - //Cb_p = sd->prev + sd->width*sd->height; - //Cr_p = sd->prev + 5*sd->width*sd->height/4; - - double minerror = 1e20; - for (i = -sd->maxshift; i <= sd->maxshift; i++) { - for (j = -sd->maxshift; j <= sd->maxshift; j++) { - double error = compareImg(Y_c, Y_p, - sd->width, sd->height, 1, i, j); -#ifdef STABVERBOSE - fprintf(f, "%i %i %f\n", i, j, error); -#endif - if (error < minerror) { - minerror = error; - x = i; - y = j; - } - } - } -#ifdef STABVERBOSE - fclose(f); - tc_log_msg(MOD_NAME, "Minerror: %f\n", minerror); -#endif - return new_transform(x, y, 0, 0, 0); -} - - - -/* calculates rotation angle for the given transform and - * field with respect to the given center-point - */ -double calcAngle(StabData* sd, Field* field, Transform* t, - int center_x, int center_y) -{ - // we better ignore fields that are to close to the rotation center - if (abs(field->x - center_x) + abs(field->y - center_y) < sd->maxshift) { - return 0; - } else { - // double r = sqrt(field->x*field->x + field->y*field->y); - double a1 = atan2(field->y - center_y, field->x - center_x); - double a2 = atan2(field->y - center_y + t->y, - field->x - center_x + t->x); - double diff = a2 - a1; - return (diff>M_PI) ? diff - 2*M_PI - : ( (diff<-M_PI) ? diff + 2*M_PI : diff); - } -} - - -/* calculates the optimal transformation for one field in YUV frames - * (only luminance) - */ -Transform calcFieldTransYUV(StabData* sd, const Field* field, int fieldnum) -{ - Transform t = null_transform(); - unsigned char *Y_c = sd->curr, *Y_p = sd->prev; - // we only use the luminance part of the image - int i, j; - -/* // check contrast in sub image */ -/* double contr = contrastSubImg(Y_c, field, sd->width, sd->height, 1); */ -/* if(contr < sd->contrast_threshold) { */ -/* t.extra=-1; */ -/* return t; */ -/* } */ -#ifdef STABVERBOSE - // printf("%i %i %f\n", sd->t, fieldnum, contr); - FILE *f = NULL; - char buffer[32]; - snprintf(buffer, sizeof(buffer), "f%04i_%02i.dat", sd->t, fieldnum); - f = fopen(buffer, "w"); - fprintf(f, "# splot \"%s\"\n", buffer); -#endif - - double minerror = 1e10; - double error = 1e10; - for (i = -sd->maxshift; i <= sd->maxshift; i += sd->stepsize) { - for (j = -sd->maxshift; j <= sd->maxshift; j += sd->stepsize) { - error = compareSubImg(Y_c, Y_p, field, - sd->width, sd->height, 1, i, j); -#ifdef STABVERBOSE - fprintf(f, "%i %i %f\n", i, j, error); -#endif - if (error < minerror) { - minerror = error; - t.x = i; - t.y = j; - } - } - } - - if (sd->stepsize > 1) { // make fine grain check around the best match - int r = sd->stepsize - 1; - for (i = t.x - r; i <= t.x + r; i += 1) { - for (j = -t.y - r; j <= t.y + r; j += 1) { - if (i == t.x && j == t.y) - continue; //no need to check this since already done - error = compareSubImg(Y_c, Y_p, field, - sd->width, sd->height, 1, i, j); -#ifdef STABVERBOSE - fprintf(f, "%i %i %f\n", i, j, error); -#endif - if (error < minerror){ - minerror = error; - t.x = i; - t.y = j; - } - } - } - } -#ifdef STABVERBOSE - fclose(f); - mlt_log_debug ( "Minerror: %f\n", minerror); -#endif - - if (!sd->allowmax && fabs(t.x) == sd->maxshift) { -#ifdef STABVERBOSE - mlt_log_debug ( "maximal x shift "); -#endif - t.x = 0; - } - if (!sd->allowmax && fabs(t.y) == sd->maxshift) { -#ifdef STABVERBOSE - mlt_log_debug ("maximal y shift "); -#endif - t.y = 0; - } - return t; -} - -/* calculates the optimal transformation for one field in RGB - * slower than the YUV version because it uses all three color channels - */ -Transform calcFieldTransRGB(StabData* sd, const Field* field, int fieldnum) -{ - Transform t = null_transform(); - unsigned char *I_c = sd->curr, *I_p = sd->prev; - int i, j; - - double minerror = 1e20; - for (i = -sd->maxshift; i <= sd->maxshift; i += 2) { - for (j=-sd->maxshift; j <= sd->maxshift; j += 2) { - double error = compareSubImg(I_c, I_p, field, - sd->width, sd->height, 3, i, j); - if (error < minerror) { - minerror = error; - t.x = i; - t.y = j; - } - } - } - for (i = t.x - 1; i <= t.x + 1; i += 2) { - for (j = -t.y - 1; j <= t.y + 1; j += 2) { - double error = compareSubImg(I_c, I_p, field, - sd->width, sd->height, 3, i, j); - if (error < minerror) { - minerror = error; - t.x = i; - t.y = j; - } - } - } - if (!sd->allowmax && fabs(t.x) == sd->maxshift) { - t.x = 0; - } - if (!sd->allowmax && fabs(t.y) == sd->maxshift) { - t.y = 0; - } - return t; -} - -/* compares contrast_idx structures respect to the contrast - (for sort function) -*/ -int cmp_contrast_idx(const void *ci1, const void* ci2) -{ - double a = ((contrast_idx*)ci1)->contrast; - double b = ((contrast_idx*)ci2)->contrast; - return a < b ? 1 : ( a > b ? -1 : 0 ); -} - -/* select only the best 'maxfields' fields - first calc contrasts then select from each part of the - frame a some fields -*/ -tlist* selectfields(StabData* sd, contrastSubImgFunc contrastfunc) -{ - int i,j; - tlist* goodflds = tlist_new(0); - contrast_idx *ci = malloc(sizeof(contrast_idx) * sd->field_num); - - // we split all fields into row+1 segments and take from each segment - // the best fields - int numsegms = (sd->field_rows+1); - int segmlen = sd->field_num/(sd->field_rows+1)+1; - // split the frame list into rows+1 segments - contrast_idx *ci_segms = malloc(sizeof(contrast_idx) * sd->field_num); - int remaining = 0; - // calculate contrast for each field - for (i = 0; i < sd->field_num; i++) { - ci[i].contrast = contrastfunc(sd, &sd->fields[i]); - ci[i].index=i; - if(ci[i].contrast < sd->contrast_threshold) ci[i].contrast = 0; - // else printf("%i %lf\n", ci[i].index, ci[i].contrast); - } - - memcpy(ci_segms, ci, sizeof(contrast_idx) * sd->field_num); - // get best fields from each segment - for(i=0; i sd->field_num ? sd->field_num : endindex; - //printf("Segment: %i: %i-%i\n", i, startindex, endindex); - - // sort within segment - qsort(ci_segms+startindex, endindex-startindex, - sizeof(contrast_idx), cmp_contrast_idx); - // take maxfields/numsegms - for(j=0; jmaxfields/numsegms; j++){ - if(startindex+j >= endindex) continue; - // printf("%i %lf\n", ci_segms[startindex+j].index, - // ci_segms[startindex+j].contrast); - if(ci_segms[startindex+j].contrast > 0){ - tlist_append(goodflds, &ci[ci_segms[startindex+j].index],sizeof(contrast_idx)); - // don't consider them in the later selection process - ci_segms[startindex+j].contrast=0; - } - } - } - // check whether enough fields are selected - // printf("Phase2: %i\n", tc_list_size(goodflds)); - remaining = sd->maxfields - tlist_size(goodflds); - if(remaining > 0){ - // take the remaining from the leftovers - qsort(ci_segms, sd->field_num, - sizeof(contrast_idx), cmp_contrast_idx); - for(j=0; j < remaining; j++){ - if(ci_segms[j].contrast > 0){ - tlist_append(goodflds, &ci_segms[j], sizeof(contrast_idx)); - } - } - } - // printf("Ende: %i\n", tc_list_size(goodflds)); - free(ci); - free(ci_segms); - return goodflds; -} - - - -/* tries to register current frame onto previous frame. - * Algorithm: - * check all fields for vertical and horizontal transformation - * use minimal difference of all possible positions - * discards fields with low contrast - * select maxfields field according to their contrast - * calculate shift as cleaned mean of all remaining fields - * calculate rotation angle of each field in respect to center of fields - * after shift removal - * calculate rotation angle as cleaned mean of all angles - * compensate for possibly off-center rotation -*/ -Transform calcTransFields(StabData* sd, calcFieldTransFunc fieldfunc, - contrastSubImgFunc contrastfunc) -{ - Transform* ts = malloc(sizeof(Transform) * sd->field_num); - Field** fs = malloc(sizeof(Field*) * sd->field_num); - double *angles = malloc(sizeof(double) * sd->field_num); - int i, index=0, num_trans; - Transform t; -#ifdef STABVERBOSE - FILE *f = NULL; - char buffer[32]; - tc_snprintf(buffer, sizeof(buffer), "k%04i.dat", sd->t); - f = fopen(buffer, "w"); - fprintf(f, "# plot \"%s\" w l, \"\" every 2:1:0\n", buffer); -#endif - - - tlist* goodflds = selectfields(sd, contrastfunc); - - // use all "good" fields and calculate optimal match to previous frame - contrast_idx* f; - while((f = (contrast_idx*)tlist_pop(goodflds,0) ) != 0){ - int i = f->index; - t = fieldfunc(sd, &sd->fields[i], i); // e.g. calcFieldTransYUV -#ifdef STABVERBOSE - fprintf(f, "%i %i\n%f %f %i\n \n\n", sd->fields[i].x, sd->fields[i].y, - sd->fields[i].x + t.x, sd->fields[i].y + t.y, t.extra); -#endif - if (t.extra != -1){ // ignore if extra == -1 (unused at the moment) - ts[index] = t; - fs[index] = sd->fields+i; - index++; - } - } - tlist_fini(goodflds); - - t = null_transform(); - num_trans = index; // amount of transforms we actually have - if (num_trans < 1) { - printf( "too low contrast! No field remains.\n" - "(no translations are detected in frame %i)", sd->t); - free(ts); - free(fs); - free(angles); - return t; - } - - int center_x = 0; - int center_y = 0; - // calc center point of all remaining fields - for (i = 0; i < num_trans; i++) { - center_x += fs[i]->x; - center_y += fs[i]->y; - } - center_x /= num_trans; - center_y /= num_trans; - - if (sd->show){ // draw fields and transforms into frame. - // this has to be done one after another to handle possible overlap - if (sd->show > 1) { - for (i = 0; i < num_trans; i++) - drawFieldScanArea(sd, fs[i], &ts[i]); - } - for (i = 0; i < num_trans; i++) - drawField(sd, fs[i], &ts[i]); - for (i = 0; i < num_trans; i++) - drawFieldTrans(sd, fs[i], &ts[i]); - } - /* median over all transforms - t= median_xy_transform(ts, sd->field_num);*/ - // cleaned mean - t = cleanmean_xy_transform(ts, num_trans); - - // subtract avg - for (i = 0; i < num_trans; i++) { - ts[i] = sub_transforms(&ts[i], &t); - } - // figure out angle - if (sd->field_num < 6) { - // the angle calculation is inaccurate for 5 and less fields - t.alpha = 0; - } else { - for (i = 0; i < num_trans; i++) { - angles[i] = calcAngle(sd, fs[i], &ts[i], center_x, center_y); - } - double min,max; - t.alpha = -cleanmean(angles, num_trans, &min, &max); - if(max-min>sd->maxanglevariation){ - t.alpha=0; - printf( "too large variation in angle(%f)\n", - max-min); - } - } - - // compensate for off-center rotation - double p_x = (center_x - sd->width/2); - double p_y = (center_y - sd->height/2); - t.x += (cos(t.alpha)-1)*p_x - sin(t.alpha)*p_y; - t.y += sin(t.alpha)*p_x + (cos(t.alpha)-1)*p_y; - -#ifdef STABVERBOSE - fclose(f); -#endif - free(ts); - free(fs); - free(angles); - return t; -} - -/** draws the field scanning area */ -void drawFieldScanArea(StabData* sd, const Field* field, const Transform* t) -{ - if (sd->pixelformat != mlt_image_yuv420p) { - mlt_log_warning (NULL, "format not usable\n"); - return; - } - drawBox(sd->curr, sd->width, sd->height, 1, field->x, field->y, - field->size+2*sd->maxshift, field->size+2*sd->maxshift, 80); -} - -/** draws the field */ -void drawField(StabData* sd, const Field* field, const Transform* t) -{ - if (sd->pixelformat != mlt_image_yuv420p){ - mlt_log_warning (NULL, "format not usable\n"); - return; - } - drawBox(sd->curr, sd->width, sd->height, 1, field->x, field->y, - field->size, field->size, t->extra == -1 ? 100 : 40); -} - -/** draws the transform data of this field */ -void drawFieldTrans(StabData* sd, const Field* field, const Transform* t) -{ - if (sd->pixelformat != mlt_image_yuv420p){ - mlt_log_warning (NULL, "format not usable\n"); - return; - } - drawBox(sd->curr, sd->width, sd->height, 1, - field->x, field->y, 5, 5, 128); // draw center - drawBox(sd->curr, sd->width, sd->height, 1, - field->x + t->x, field->y + t->y, 8, 8, 250); // draw translation -} - -/** - * draws a box at the given position x,y (center) in the given color - (the same for all channels) - */ -void drawBox(unsigned char* I, int width, int height, int bytesPerPixel, - int x, int y, int sizex, int sizey, unsigned char color){ - - unsigned char* p = NULL; - int j,k; - p = I + ((x - sizex/2) + (y - sizey/2)*width)*bytesPerPixel; - for (j = 0; j < sizey; j++){ - for (k = 0; k < sizex * bytesPerPixel; k++) { - *p = color; - p++; - } - p += (width - sizex) * bytesPerPixel; - } -} - -struct iterdata { - FILE *f; - int counter; -}; - -/*************************************************************************/ - -/* Module interface routines and data. */ - -/*************************************************************************/ - -/* - * stabilize_configure: Configure this instance of the module. See - * tcmodule-data.h for function details. - */ -int stabilize_configure(StabData* instance -/*const char *options, - int pixelfmt */ - /*TCModuleExtraData *xdata[]*/) -{ - StabData *sd = instance; - /* sd->framesize = sd->vob->im_v_width * MAX_PLANES * - sizeof(char) * 2 * sd->vob->im_v_height * 2; */ - /*TODO sd->framesize = sd->vob->im_v_size; */ - sd->prev = calloc(1,sd->framesize); - sd->grayimage = calloc(1,sd->width*sd->height); - - if (!sd->prev || !sd->grayimage) { - printf( "malloc failed"); - return -1; - } - sd->currcopy = 0; - sd->hasSeenOneFrame = 0; - sd->transs = 0; - sd->allowmax = 0; - sd->field_size = MIN(sd->width, sd->height)/12; - sd->maxanglevariation = 1; - - sd->shakiness = MIN(10,MAX(1,sd->shakiness)); - sd->accuracy = MAX(sd->shakiness,MIN(15,MAX(1,sd->accuracy))); - if (1) { - mlt_log_debug (NULL, "Image Stabilization Settings:\n"); - mlt_log_debug (NULL, " shakiness = %d\n", sd->shakiness); - mlt_log_debug (NULL, " accuracy = %d\n", sd->accuracy); - mlt_log_debug (NULL, " stepsize = %d\n", sd->stepsize); - mlt_log_debug (NULL, " algo = %d\n", sd->algo); - mlt_log_debug (NULL, " mincontrast = %f\n", sd->contrast_threshold); - mlt_log_debug (NULL, " show = %d\n", sd->show); - } - -#ifndef USE_SSE2 - mlt_log_info(NULL,"No SSE2 support enabled, this will slow down a lot\n"); -#endif - // shift and size: shakiness 1: height/40; 10: height/4 - sd->maxshift = MIN(sd->width, sd->height)*sd->shakiness/40; - sd->field_size = MIN(sd->width, sd->height)*sd->shakiness/40; - - mlt_log_debug ( NULL, "Fieldsize: %i, Maximal translation: %i pixel\n", - sd->field_size, sd->maxshift); - if (sd->algo==1) { - // initialize measurement fields. field_num is set here. - if (!initFields(sd)) { - return -1; - } - sd->maxfields = (sd->accuracy) * sd->field_num / 15; - mlt_log_debug ( NULL, "Number of used measurement fields: %i out of %i\n", - sd->maxfields, sd->field_num); - } - if (sd->show){ - sd->currcopy = calloc(1,sd->framesize); - } - - /* load unsharp filter to smooth the frames. This allows larger stepsize.*/ - char unsharp_param[128]; - int masksize = MIN(13,sd->stepsize*1.8); // only works up to 13. - sprintf(unsharp_param,"luma=-1:luma_matrix=%ix%i:pre=1", - masksize, masksize); - return 0; -} - - -/** - * stabilize_filter_video: performs the analysis of subsequent frames - * See tcmodule-data.h for function details. - */ - -int stabilize_filter_video(StabData* instance, - unsigned char *frame,mlt_image_format pixelformat) -{ - StabData *sd = instance; - sd->pixelformat=pixelformat; - int l=sd->width*sd->height; - unsigned char* tmpgray=sd->grayimage; - if (pixelformat == mlt_image_yuv422){ - while(l--){ - *tmpgray++=*frame++; - frame++; - }; - } - - if(sd->show) { // save the buffer to restore at the end for prev - if (pixelformat == mlt_image_yuv420p){ - memcpy(sd->currcopy, sd->grayimage, sd->framesize); - } - } - if (sd->hasSeenOneFrame) { - sd->curr = sd->grayimage; - if (pixelformat == mlt_image_rgb24) { - if (sd->algo == 0) - addTrans(sd, calcShiftRGBSimple(sd)); - else if (sd->algo == 1) - addTrans(sd, calcTransFields(sd, calcFieldTransRGB, - contrastSubImgRGB)); - } else if (pixelformat == mlt_image_yuv420p ) { - if (sd->algo == 0) - addTrans(sd, calcShiftYUVSimple(sd)); - else if (sd->algo == 1) - addTrans(sd, calcTransFields(sd, calcFieldTransYUV, - contrastSubImgYUV)); - } else if (pixelformat == mlt_image_yuv422 ) { - if (sd->algo == 0) - addTrans(sd, calcShiftYUVSimple(sd)); - else if (sd->algo == 1) - addTrans(sd, calcTransFields(sd, calcFieldTransYUV, - contrastSubImgYUV)); - } else { - mlt_log_warning (NULL,"unsupported Codec: %i\n", - pixelformat); - return 0; - } - } else { - sd->hasSeenOneFrame = 1; - addTrans(sd, null_transform()); - } - - if(!sd->show) { // copy current frame to prev for next frame comparison - memcpy(sd->prev, sd->grayimage, sd->framesize); - } else { // use the copy because we changed the original frame - memcpy(sd->prev, sd->currcopy, sd->framesize); - } - sd->t++; - return 0; -} - -/** - * stabilize_stop: Reset this instance of the module. See tcmodule-data.h - * for function details. - */ - -int stabilize_stop(StabData* instance) -{ - StabData *sd = instance; - free(sd->prev); - sd->prev = NULL; - free(sd->grayimage); - sd->grayimage=NULL; - return 0; -} - - - diff --git a/src/modules/videostab/stabilize.h b/src/modules/videostab/stabilize.h deleted file mode 100644 index 8e7ac96c7..000000000 --- a/src/modules/videostab/stabilize.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * filter_stabilize.c - * - * Copyright (C) Georg Martius - June 2007 - * georg dot martius at web dot de - * - * This file is part of transcode, a video stream processing tool - * - * transcode is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * transcode is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -/* Typical call: - * transcode -V -J stabilize=shakiness=5:show=1,preview - * -i inp.mpeg -y null,null -o dummy - * all parameters are optional -*/ - -#define MOD_NAME "filter_stabilize.so" -#define MOD_VERSION "v0.75 (2010-04-07)" -#define MOD_CAP "extracts relative transformations of \n\ - subsequent frames (used for stabilization together with the\n\ - transform filter in a second pass)" -#define MOD_AUTHOR "Georg Martius" - -/* Ideas: - - Try OpenCL/Cuda, this should work great - - use smoothing on the frames and then use gradient decent! - - stepsize could be adapted (maybe to check only one field with large - stepsize and use the maximally required for the other fields -*/ - -#define MOD_FEATURES \ - TC_MODULE_FEATURE_FILTER|TC_MODULE_FEATURE_VIDEO -#define MOD_FLAGS \ - TC_MODULE_FLAG_RECONFIGURABLE | TC_MODULE_FLAG_DELAY - - -#include "transform.h" - -#include -#include -#include -#include "tlist.h" -#include - -/* if defined we are very verbose and generate files to analyse - * this is really just for debugging and development */ -// #define STABVERBOSE - - -typedef struct _field { - int x; // middle position x - int y; // middle position y - int size; // size of field -} Field; - -// structure that contains the contrast and the index of a field -typedef struct _contrast_idx { - double contrast; - int index; -} contrast_idx; - -/* private date structure of this filter*/ -typedef struct _stab_data { - int framesize; // size of frame buffer in bytes (prev) - unsigned char* curr; // current frame buffer (only pointer) - unsigned char* currcopy; // copy of the current frame needed for drawing - unsigned char* prev; // frame buffer for last frame (copied) - unsigned char* grayimage; // frame buffer for last frame (copied) - short hasSeenOneFrame; // true if we have a valid previous frame - - int width, height; - mlt_image_format pixelformat; - - /* list of transforms*/ - //TCList* transs; - tlist* transs; - - Field* fields; - - - /* Options */ - /* maximum number of pixels we expect the shift of subsequent frames */ - int maxshift; - int stepsize; // stepsize of field transformation detection - int allowmax; // 1 if maximal shift is allowed - int algo; // algorithm to use - int field_num; // number of measurement fields - int maxfields; // maximum number of fields used (selected by contrast) - int field_size; // size = min(sd->width, sd->height)/10; - int field_rows; // number of rows - /* if 1 and 2 then the fields and transforms are shown in the frames */ - int show; - /* measurement fields with lower contrast are discarded */ - double contrast_threshold; - /* maximal difference in angles of fields */ - double maxanglevariation; - /* meta parameter for maxshift and fieldsize between 1 and 10 */ - int shakiness; - int accuracy; // meta parameter for number of fields between 1 and 10 - - int t; - - char conf_str[1024]; -} StabData; - -/* type for a function that calculates the transformation of a certain field - */ -typedef Transform (*calcFieldTransFunc)(StabData*, const Field*, int); - -/* type for a function that calculates the contrast of a certain field - */ -typedef double (*contrastSubImgFunc)(StabData* sd, const Field* field); - -static const char stabilize_help[] = "" - "Overview:\n" - " Generates a file with relative transform information\n" - " (translation, rotation) about subsequent frames." - " See also transform.\n" - "Options\n" - " 'result' path to the file used to write the transforms\n" - " (def:inputfile.stab)\n" - " 'shakiness' how shaky is the video and how quick is the camera?\n" - " 1: little (fast) 10: very strong/quick (slow) (def: 4)\n" - " 'accuracy' accuracy of detection process (>=shakiness)\n" - " 1: low (fast) 15: high (slow) (def: 4)\n" - " 'stepsize' stepsize of search process, region around minimum \n" - " is scanned with 1 pixel resolution (def: 6)\n" - " 'algo' 0: brute force (translation only);\n" - " 1: small measurement fields (def)\n" - " 'mincontrast' below this contrast a field is discarded (0-1) (def: 0.3)\n" - " 'show' 0: draw nothing (def); 1,2: show fields and transforms\n" - " in the resulting frames. Consider the 'preview' filter\n" - " 'help' print this help message\n"; - -int initFields(StabData* sd); -double compareImg(unsigned char* I1, unsigned char* I2, - int width, int height, int bytesPerPixel, int d_x, int d_y); -double compareSubImg(unsigned char* const I1, unsigned char* const I2, - const Field* field, - int width, int height, int bytesPerPixel,int d_x,int d_y); -double contrastSubImgYUV(StabData* sd, const Field* field); -double contrastSubImgRGB(StabData* sd, const Field* field); -double contrastSubImg(unsigned char* const I, const Field* field, - int width, int height, int bytesPerPixel); -int cmp_contrast_idx(const void *ci1, const void* ci2); -tlist* selectfields(StabData* sd, contrastSubImgFunc contrastfunc); - -Transform calcShiftRGBSimple(StabData* sd); -Transform calcShiftYUVSimple(StabData* sd); -double calcAngle(StabData* sd, Field* field, Transform* t, - int center_x, int center_y); -Transform calcFieldTransYUV(StabData* sd, const Field* field, - int fieldnum); -Transform calcFieldTransRGB(StabData* sd, const Field* field, - int fieldnum); -Transform calcTransFields(StabData* sd, calcFieldTransFunc fieldfunc, - contrastSubImgFunc contrastfunc); - - -void drawFieldScanArea(StabData* sd, const Field* field, const Transform* t); -void drawField(StabData* sd, const Field* field, const Transform* t); -void drawFieldTrans(StabData* sd, const Field* field, const Transform* t); -void drawBox(unsigned char* I, int width, int height, int bytesPerPixel, - int x, int y, int sizex, int sizey, unsigned char color); -void addTrans(StabData* sd, Transform sl); - -int stabilize_configure(StabData* instance); -int stabilize_stop(StabData* instance); - -int stabilize_filter_video(StabData* instance, unsigned char *frame,mlt_image_format imageformat); - - diff --git a/src/modules/videostab/tlist.c b/src/modules/videostab/tlist.c deleted file mode 100644 index 2746dc3fd..000000000 --- a/src/modules/videostab/tlist.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "tlist.h" -#include -#include - -tlist* tlist_new(int size){ - tlist* t=malloc(sizeof(tlist)); - memset(t,0,sizeof(tlist)); - return t; -} - -void tlist_append(tlist* t,void* data,int size){ - tlist* next=tlist_new(0); - tlist* pos=t; - while (pos && pos->next) { - pos=pos->next; - } - - pos->data=malloc(size); - memcpy(pos->data,data,size); - pos->next=next; -} -int tlist_size(tlist* t){ - int ret=0; - tlist* pos=t; - while (pos && pos->next && pos->data) { - pos=pos->next ; - ret++; - }; - return ret; -} -void* tlist_pop(tlist* t,int at){ - int ret=0; - tlist* pos=t; - /*if (pos && !pos->next ){ - return pos->data; - }*/ - while (pos && pos->next) { - if (ret==at){ - tlist* n=pos->next; - pos->data=n->data; - pos->next=n->next; - return pos->data; - } - pos=pos->next ; - ret++; - }; - return NULL; -} -void tlist_fini(tlist* list){ - tlist* head=list; - while (head){ - free(head->data); - tlist *del=head; - head=head->next; - free(del); - } -} diff --git a/src/modules/videostab/tlist.h b/src/modules/videostab/tlist.h deleted file mode 100644 index 3ba1b995c..000000000 --- a/src/modules/videostab/tlist.h +++ /dev/null @@ -1,18 +0,0 @@ - - -#ifndef __TLIST__ -#define __TLIST__ - -typedef struct _tlist { - void* data; - void* next; -} tlist; - - -tlist* tlist_new(int size); -void tlist_append(tlist* t,void* data,int size); -int tlist_size(tlist* t); -void* tlist_pop(tlist* t,int at); -void tlist_fini(tlist* ); - -#endif diff --git a/src/modules/videostab/transform.c b/src/modules/videostab/transform.c deleted file mode 100644 index 14d04af5a..000000000 --- a/src/modules/videostab/transform.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * transform.c - * - * Copyright (C) Georg Martius - June 2007 - * - * This file is part of transcode, a video stream processing tool - * - * transcode is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * transcode is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include -#include -#include -#include "transform.h" - -/*********************************************************************** - * helper functions to create and operate with transforms. - * all functions are non-destructive - */ - -/* create an initialized transform*/ -Transform new_transform(double x, double y, double alpha, - double zoom, int extra) -{ - Transform t; - t.x = x; - t.y = y; - t.alpha = alpha; - t.zoom = zoom; - t.extra = extra; - return t; -} - -/* create a zero initialized transform*/ -Transform null_transform(void) -{ - return new_transform(0, 0, 0, 0, 0); -} - -/* adds two transforms */ -Transform add_transforms(const Transform* t1, const Transform* t2) -{ - Transform t; - t.x = t1->x + t2->x; - t.y = t1->y + t2->y; - t.alpha = t1->alpha + t2->alpha; - t.zoom = t1->zoom + t2->zoom; - t.extra = 0; - return t; -} - -/* like add_transform but with non-pointer signature */ -Transform add_transforms_(const Transform t1, const Transform t2) -{ - return add_transforms(&t1, &t2); -} - -/* subtracts two transforms */ -Transform sub_transforms(const Transform* t1, const Transform* t2) -{ - Transform t; - t.x = t1->x - t2->x; - t.y = t1->y - t2->y; - t.alpha = t1->alpha - t2->alpha; - t.zoom = t1->zoom - t2->zoom; - t.extra = 0; - return t; -} - -/* multiplies a transforms with a scalar */ -Transform mult_transform(const Transform* t1, double f) -{ - Transform t; - t.x = t1->x * f; - t.y = t1->y * f; - t.alpha = t1->alpha * f; - t.zoom = t1->zoom * f; - t.extra = 0; - return t; -} - -/* like mult_transform but with non-pointer signature */ -Transform mult_transform_(const Transform t1, double f) -{ - return mult_transform(&t1,f); -} - -/* compares a transform with respect to x (for sort function) */ -int cmp_trans_x(const void *t1, const void* t2) -{ - double a = ((Transform*)t1)->x; - double b = ((Transform*)t2)->x; - return a < b ? -1 : ( a > b ? 1 : 0 ); -} - -/* compares a transform with respect to y (for sort function) */ -int cmp_trans_y(const void *t1, const void* t2) -{ - double a = ((Transform*)t1)->y; - double b = ((Transform*)t2)->y; - return a < b ? -1 : ( a > b ? 1: 0 ); -} - -/* static int cmp_trans_alpha(const void *t1, const void* t2){ */ -/* double a = ((Transform*)t1)->alpha; */ -/* double b = ((Transform*)t2)->alpha; */ -/* return a < b ? -1 : ( a > b ? 1 : 0 ); */ -/* } */ - - -/* compares two double values (for sort function)*/ -int cmp_double(const void *t1, const void* t2) -{ - double a = *((double*)t1); - double b = *((double*)t2); - return a < b ? -1 : ( a > b ? 1 : 0 ); -} - -/** - * median_xy_transform: calulcates the median of an array - * of transforms, considering only x and y - * - * Parameters: - * transforms: array of transforms. - * len: length of array - * Return value: - * A new transform with x and y being the median of - * all transforms. alpha and other fields are 0. - * Preconditions: - * len>0 - * Side effects: - * None - */ -Transform median_xy_transform(const Transform* transforms, int len) -{ - Transform* ts = malloc(sizeof(Transform) * len); - Transform t; - memcpy(ts,transforms, sizeof(Transform)*len ); - int half = len/2; - qsort(ts, len, sizeof(Transform), cmp_trans_x); - t.x = len % 2 == 0 ? ts[half].x : (ts[half].x + ts[half+1].x)/2; - qsort(ts, len, sizeof(Transform), cmp_trans_y); - t.y = len % 2 == 0 ? ts[half].y : (ts[half].y + ts[half+1].y)/2; - t.alpha = 0; - t.zoom = 0; - t.extra = 0; - free(ts); - return t; -} - -/** - * cleanmean_xy_transform: calulcates the cleaned mean of an array - * of transforms, considering only x and y - * - * Parameters: - * transforms: array of transforms. - * len: length of array - * Return value: - * A new transform with x and y being the cleaned mean - * (meaning upper and lower pentile are removed) of - * all transforms. alpha and other fields are 0. - * Preconditions: - * len>0 - * Side effects: - * None - */ -Transform cleanmean_xy_transform(const Transform* transforms, int len) -{ - Transform* ts = malloc(sizeof(Transform) * len); - Transform t = null_transform(); - int i, cut = len / 5; - memcpy(ts, transforms, sizeof(Transform) * len); - qsort(ts,len, sizeof(Transform), cmp_trans_x); - for (i = cut; i < len - cut; i++){ // all but cutted - t.x += ts[i].x; - } - qsort(ts, len, sizeof(Transform), cmp_trans_y); - for (i = cut; i < len - cut; i++){ // all but cutted - t.y += ts[i].y; - } - free(ts); - return mult_transform(&t, 1.0 / (len - (2.0 * cut))); -} - - -/** - * calulcates the cleaned maximum and minimum of an array of transforms, - * considerung only x and y - * It cuts off the upper and lower x-th percentil - * - * Parameters: - * transforms: array of transforms. - * len: length of array - * percentil: the x-th percentil to cut off - * min: pointer to min (return value) - * max: pointer to max (return value) - * Return value: - * call by reference in min and max - * Preconditions: - * len>0, 0<=percentil<50 - * Side effects: - * only on min and max - */ -void cleanmaxmin_xy_transform(const Transform* transforms, int len, - int percentil, - Transform* min, Transform* max){ - Transform* ts = malloc(sizeof(Transform) * len); - int cut = len * percentil / 100; - memcpy(ts, transforms, sizeof(Transform) * len); - qsort(ts,len, sizeof(Transform), cmp_trans_x); - min->x = ts[cut].x; - max->x = ts[len-cut-1].x; - qsort(ts, len, sizeof(Transform), cmp_trans_y); - min->y = ts[cut].y; - max->y = ts[len-cut-1].y; - free(ts); -} - - -/** - * media: median of a double array - * - * Parameters: - * ds: array of values - * len: length of array - * Return value: - * the median value of the array - * Preconditions: len>0 - * Side effects: ds will be sorted! - */ -double median(double* ds, int len) -{ - int half=len/2; - qsort(ds,len, sizeof(double), cmp_double); - return len % 2 == 0 ? ds[half] : (ds[half] + ds[half+1])/2; -} - -/** - * mean: mean of a double array - * - * Parameters: - * ds: array of values - * len: length of array - * Return value: the mean value of the array - * Preconditions: len>0 - * Side effects: None - */ -double mean(const double* ds, int len) -{ - double sum=0; - int i = 0; - for (i = 0; i < len; i++) - sum += ds[i]; - return sum / len; -} - -/** - * cleanmean: mean with cutted upper and lower pentile - * - * Parameters: - * ds: array of values - * len: length of array - * len: length of array - * minimum: minimal value (after cleaning) if not NULL - * maximum: maximal value (after cleaning) if not NULL - * Return value: - * the mean value of the array without the upper - * and lower pentile (20% each) - * and lower pentile (20% each) - * and minimum and maximum without the pentiles - * Preconditions: len>0 - * Side effects: ds will be sorted! - */ -double cleanmean(double* ds, int len, double* minimum, double* maximum) -{ - int cut = len / 5; - double sum = 0; - int i = 0; - qsort(ds, len, sizeof(double), cmp_double); - for (i = cut; i < len - cut; i++) { // all but first and last - sum += ds[i]; - } - if (minimum) - *minimum = ds[cut]; - if (maximum) - *maximum = ds[len-cut-1]; - return sum / (len - (2.0 * cut)); -} - - -/* - * Local variables: - * c-file-style: "stroustrup" - * c-file-offsets: ((case-label . *) (statement-case-intro . *)) - * indent-tabs-mode: nil - * End: - * - * vim: expandtab shiftwidth=4: - */ diff --git a/src/modules/videostab/transform.h b/src/modules/videostab/transform.h deleted file mode 100644 index 0b959389a..000000000 --- a/src/modules/videostab/transform.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * transform.h - * - * Copyright (C) Georg Martius - June 2007 - * - * This file is part of transcode, a video stream processing tool - * - * transcode is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * transcode is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ -#ifndef __TRANSFORM_H -#define __TRANSFORM_H - -#define DEFAULT_TRANS_FILE_NAME "transforms.dat" - -/* structure to hold information about frame transformations - x,y are translations, alpha is a rotation around the center in RAD, - zoom is a percentage to zoom in and - extra is for additional information like scene cut (unused) - */ -typedef struct _transform { - double x; - double y; - double alpha; - double zoom; - int extra; /* -1: ignore transform (only internal use); - 0 for normal trans; 1 for inter scene cut (unused) */ -} Transform; - -/* helper functions to create and operate with transforms. - * all functions are non-destructive - * the "_" version uses non-pointer Transforms. This is slower - * but useful when cascading calculations like - * add_transforms_(mult_transform(&t1, 5.0), &t2) - */ -Transform null_transform(void); -Transform new_transform(double x, double y, double alpha, - double zoom, int extra); -Transform add_transforms(const Transform* t1, const Transform* t2); -Transform add_transforms_(const Transform t1, const Transform t2); -Transform sub_transforms(const Transform* t1, const Transform* t2); -Transform mult_transform(const Transform* t1, double f); -Transform mult_transform_(const Transform t1, double f); - -/* compares a transform with respect to x (for sort function) */ -int cmp_trans_x(const void *t1, const void* t2); -/* compares a transform with respect to y (for sort function) */ -int cmp_trans_y(const void *t1, const void* t2); -/* static int cmp_trans_alpha(const void *t1, const void* t2); */ - -/* compares two double values (for sort function)*/ -int cmp_double(const void *t1, const void* t2); - -/* calculates the median of an array of transforms, - * considering only x and y - */ -Transform median_xy_transform(const Transform* transforms, int len); -/* median of a double array */ -double median(double* ds, int len); -/* mean of a double array */ -double mean(const double* ds, int len); -/* mean with cutted upper and lower pentile - * (min and max are optionally returned) - */ -double cleanmean(double* ds, int len, double* minimum, double* maximum); -/* calculates the cleaned mean of an array of transforms, - * considering only x and y - */ -Transform cleanmean_xy_transform(const Transform* transforms, int len); - -/* calculates the cleaned (cutting of x-th percentil) - * maximum and minimum of an array of transforms, - * considerung only x and y - */ -void cleanmaxmin_xy_transform(const Transform* transforms, int len, - int percentil, - Transform* min, Transform* max); - -/* helper functions */ - -/* optimized round function */ -inline static int myround(float x) { - if(x>0) - return x + 0.5; - else - return x - 0.5; -} - - -/* optimized floor function - This does not give the correct value for negative integer values like -1.0. In this case - it will produce -2.0. -*/ -inline static int myfloor(float x) { - if(x<0) - return x - 1; - else - return x; -} - - -#endif - -/* - * Local variables: - * c-file-style: "stroustrup" - * c-file-offsets: ((case-label . *) (statement-case-intro . *)) - * indent-tabs-mode: nil - * End: - * - * vim: expandtab shiftwidth=4: - */ diff --git a/src/modules/videostab/transform_image.c b/src/modules/videostab/transform_image.c deleted file mode 100644 index ff0710baa..000000000 --- a/src/modules/videostab/transform_image.c +++ /dev/null @@ -1,714 +0,0 @@ -/* - * filter_transform.c - * - * Copyright (C) Georg Martius - June 2007 - * georg dot martius at web dot de - * - * This file is part of transcode, a video stream processing tool - * - * transcode is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * transcode is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Typical call: - * transcode -J transform -i inp.mpeg -y xdiv,tcaud inp_stab.avi - */ -#include "transform_image.h" -#include -#include -#include - -#define TC_MAX(a, b) (((a) > (b)) ?(a) :(b)) -#define TC_MIN(a, b) (((a) < (b)) ?(a) :(b)) -/* clamp x between a and b */ -#define TC_CLAMP(x, a, b) TC_MIN(TC_MAX((a), (x)), (b)) - - -static const char* interpoltypes[5] = {"No (0)", "Linear (1)", "Bi-Linear (2)", - "Quadratic (3)", "Bi-Cubic (4)"}; - -void (*interpolate)(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, - unsigned char def,unsigned char N, unsigned char channel) = 0; - -/** interpolateBiLinBorder: bi-linear interpolation function that also works at the border. - This is used by many other interpolation methods at and outsize the border, see interpolate */ -void interpolateBiLinBorder(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, - unsigned char def,unsigned char N, unsigned char channel) -{ - int x_f = myfloor(x); - int x_c = x_f+1; - int y_f = myfloor(y); - int y_c = y_f+1; - short v1 = PIXELN(img, x_c, y_c, width, height, N, channel, def); - short v2 = PIXELN(img, x_c, y_f, width, height, N, channel, def); - short v3 = PIXELN(img, x_f, y_c, width, height, N, channel, def); - short v4 = PIXELN(img, x_f, y_f, width, height, N, channel, def); - float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) + - (v2*(x - x_f) + v4*(x_c - x))*(y_c - y); - *rv = (unsigned char)s; -} - -/* taken from http://en.wikipedia.org/wiki/Bicubic_interpolation for alpha=-0.5 - in matrix notation: - a0-a3 are the neigthboring points where the target point is between a1 and a2 - t is the point of interpolation (position between a1 and a2) value between 0 and 1 - | 0, 2, 0, 0 | |a0| - |-1, 0, 1, 0 | |a1| - (1,t,t^2,t^3) | 2,-5, 4,-1 | |a2| - |-1, 3,-3, 1 | |a3| -*/ -static short bicub_kernel(float t, short a0, short a1, short a2, short a3){ - return (2*a1 + t*((-a0+a2) + t*((2*a0-5*a1+4*a2-a3) + t*(-a0+3*a1-3*a2+a3) )) ) / 2; -} - -/** interpolateBiCub: bi-cubic interpolation function using 4x4 pixel, see interpolate */ -void interpolateBiCub(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel) -{ - // do a simple linear interpolation at the border - if (x < 1 || x >= width-2 || y < 1 || y >= height - 2) { - interpolateBiLinBorder(rv, x,y,img,width,height,def,N,channel); - } else { - int x_f = myfloor(x); - int y_f = myfloor(y); - float tx = x-x_f; - short v1 = bicub_kernel(tx, - PIXN(img, x_f-1, y_f-1, width, height, N, channel), - PIXN(img, x_f, y_f-1, width, height, N, channel), - PIXN(img, x_f+1, y_f-1, width, height, N, channel), - PIXN(img, x_f+2, y_f-1, width, height, N, channel)); - short v2 = bicub_kernel(tx, - PIXN(img, x_f-1, y_f, width, height, N, channel), - PIXN(img, x_f, y_f, width, height, N, channel), - PIXN(img, x_f+1, y_f, width, height, N, channel), - PIXN(img, x_f+2, y_f, width, height, N, channel)); - short v3 = bicub_kernel(tx, - PIXN(img, x_f-1, y_f+1, width, height, N, channel), - PIXN(img, x_f, y_f+1, width, height, N, channel), - PIXN(img, x_f+1, y_f+1, width, height, N, channel), - PIXN(img, x_f+2, y_f+1, width, height, N, channel)); - short v4 = bicub_kernel(tx, - PIXN(img, x_f-1, y_f+2, width, height, N, channel), - PIXN(img, x_f, y_f+2, width, height, N, channel), - PIXN(img, x_f+1, y_f+2, width, height, N, channel), - PIXN(img, x_f+2, y_f+2, width, height, N, channel)); - *rv = (unsigned char)bicub_kernel(y-y_f, v1, v2, v3, v4); - } -} - -/** interpolateSqr: bi-quatratic interpolation function, see interpolate */ -void interpolateSqr(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel) -{ - if (x < 0 || x >= width-1 || y < 0 || y >= height-1) { - interpolateBiLinBorder(rv, x, y, img, width, height, def,N,channel); - } else { - int x_f = myfloor(x); - int x_c = x_f+1; - int y_f = myfloor(y); - int y_c = y_f+1; - short v1 = PIXN(img, x_c, y_c, width, height, N, channel); - short v2 = PIXN(img, x_c, y_f, width, height, N, channel); - short v3 = PIXN(img, x_f, y_c, width, height, N, channel); - short v4 = PIXN(img, x_f, y_f, width, height, N, channel); - float f1 = 1 - sqrt((x_c - x) * (y_c - y)); - float f2 = 1 - sqrt((x_c - x) * (y - y_f)); - float f3 = 1 - sqrt((x - x_f) * (y_c - y)); - float f4 = 1 - sqrt((x - x_f) * (y - y_f)); - float s = (v1*f1 + v2*f2 + v3*f3+ v4*f4)/(f1 + f2 + f3 + f4); - *rv = (unsigned char)s; - } -} - -/** interpolateBiLin: bi-linear interpolation function, see interpolate */ -void interpolateBiLin(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, - unsigned char def,unsigned char N, unsigned char channel) -{ - if (x < 0 || x >= width-1 || y < 0 || y >= height - 1) { - interpolateBiLinBorder(rv, x, y, img, width, height, def,N,channel); - } else { - int x_f = myfloor(x); - int x_c = x_f+1; - int y_f = myfloor(y); - int y_c = y_f+1; - short v1 = PIXN(img, x_c, y_c, width, height, N, channel); - short v2 = PIXN(img, x_c, y_f, width, height, N, channel); - short v3 = PIXN(img, x_f, y_c, width, height, N, channel); - short v4 = PIXN(img, x_f, y_f, width, height, N, channel); - float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) + - (v2*(x - x_f) + v4*(x_c - x))*(y_c - y); - *rv = (unsigned char)s; - } -} - - -/** interpolateLin: linear (only x) interpolation function, see interpolate */ -void interpolateLin(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, - unsigned char def,unsigned char N, unsigned char channel) -{ - int x_f = myfloor(x); - int x_c = x_f+1; - int y_n = myround(y); - float v1 = PIXELN(img, x_c, y_n, width, height, N, channel,def); - float v2 = PIXELN(img, x_f, y_n, width, height, N, channel,def); - float s = v1*(x - x_f) + v2*(x_c - x); - *rv = (unsigned char)s; -} - -/** interpolateZero: nearest neighbor interpolation function, see interpolate */ -void interpolateZero(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel) -{ - int x_n = myround(x); - int y_n = myround(y); - *rv = (unsigned char) PIXELN(img, x_n, y_n, width, height, N,channel,def); -} - - -/** - * interpolateN: Bi-linear interpolation function for N channel image. - * - * Parameters: - * rv: destination pixel (call by reference) - * x,y: the source coordinates in the image img. Note this - * are real-value coordinates, that's why we interpolate - * img: source image - * width,height: dimension of image - * N: number of channels - * channel: channel number (0..N-1) - * def: default value if coordinates are out of range - * Return value: None - */ -void interpolateN(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, - unsigned char N, unsigned char channel, - unsigned char def) -{ - if (x < - 1 || x > width || y < -1 || y > height) { - *rv = def; - } else { - int x_f = myfloor(x); - int x_c = x_f+1; - int y_f = myfloor(y); - int y_c = y_f+1; - short v1 = PIXELN(img, x_c, y_c, width, height, N, channel, def); - short v2 = PIXELN(img, x_c, y_f, width, height, N, channel, def); - short v3 = PIXELN(img, x_f, y_c, width, height, N, channel, def); - short v4 = PIXELN(img, x_f, y_f, width, height, N, channel, def); - float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) + - (v2*(x - x_f) + v4*(x_c - x))*(y_c - y); - *rv = (unsigned char)s; - } -} - - -/** - * transformRGB: applies current transformation to frame - * Parameters: - * td: private data structure of this filter - * Return value: - * 0 for failure, 1 for success - * Preconditions: - * The frame must be in RGB format - */ -int transformRGB(TransformData* td) -{ - Transform t; - int x = 0, y = 0, z = 0; - unsigned char *D_1, *D_2; - t = td->trans[td->current_trans]; - - D_1 = td->src; - D_2 = td->dest; - float zm = 1.0-t.zoom/100; - float zcos_a = zm*cos(-t.alpha); // scaled cos - float zsin_a = zm*sin(-t.alpha); // scaled sin - float c_s_x = td->width_src/2.0; - float c_s_y = td->height_src/2.0; - float c_d_x = td->width_dest/2.0; - float c_d_y = td->height_dest/2.0; - - /* for each pixel in the destination image we calc the source - * coordinate and make an interpolation: - * p_d = c_d + M(p_s - c_s) + t - * where p are the points, c the center coordinate, - * _s source and _d destination, - * t the translation, and M the rotation matrix - * p_s = M^{-1}(p_d - c_d - t) + c_s - */ - /* All 3 channels */ - if (fabs(t.alpha) > td->rotation_threshhold || t.zoom != 0) { - for (x = 0; x < td->width_dest; x++) { - for (y = 0; y < td->height_dest; y++) { - float x_d1 = (x - c_d_x); - float y_d1 = (y - c_d_y); - float x_s = zcos_a * x_d1 - + zsin_a * y_d1 + c_s_x -t.x; - float y_s = -zsin_a * x_d1 - + zcos_a * y_d1 + c_s_y -t.y; - for (z = 0; z < 3; z++) { // iterate over colors - unsigned char* dest = &D_2[(x + y * td->width_dest)*3+z]; - interpolate(dest, x_s, y_s, D_1, - td->width_src, td->height_src, - td->crop ? 16 : *dest,3,z); - } - } - } - }else { - /* no rotation, just translation - *(also no interpolation, since no size change (so far) - */ - int round_tx = myround(t.x); - int round_ty = myround(t.y); - for (x = 0; x < td->width_dest; x++) { - for (y = 0; y < td->height_dest; y++) { - for (z = 0; z < 3; z++) { // iterate over colors - short p = PIXELN(D_1, x - round_tx, y - round_ty, - td->width_src, td->height_src, 3, z, -1); - if (p == -1) { - if (td->crop == 1) - D_2[(x + y * td->width_dest)*3+z] = 16; - } else { - D_2[(x + y * td->width_dest)*3+z] = (unsigned char)p; - } - } - } - } - } - return 1; -} - -/** - * transformYUV: applies current transformation to frame - * - * Parameters: - * td: private data structure of this filter - * Return value: - * 0 for failure, 1 for success - * Preconditions: - * The frame must be in YUV format - */ -int transformYUV(TransformData* td) -{ - Transform t; - int x = 0, y = 0; - unsigned char *Y_1, *Y_2, *Cb_1, *Cb_2, *Cr_1, *Cr_2; - t = td->trans[td->current_trans]; - - Y_1 = td->src; - Y_2 = td->dest; - Cb_1 = td->src + td->width_src * td->height_src; - Cb_2 = td->dest + td->width_dest * td->height_dest; - Cr_1 = td->src + 5*td->width_src * td->height_src/4; - Cr_2 = td->dest + 5*td->width_dest * td->height_dest/4; - float c_s_x = td->width_src/2.0; - float c_s_y = td->height_src/2.0; - float c_d_x = td->width_dest/2.0; - float c_d_y = td->height_dest/2.0; - - float z = 1.0-t.zoom/100; - float zcos_a = z*cos(-t.alpha); // scaled cos - float zsin_a = z*sin(-t.alpha); // scaled sin - - /* for each pixel in the destination image we calc the source - * coordinate and make an interpolation: - * p_d = c_d + M(p_s - c_s) + t - * where p are the points, c the center coordinate, - * _s source and _d destination, - * t the translation, and M the rotation and scaling matrix - * p_s = M^{-1}(p_d - c_d - t) + c_s - */ - /* Luminance channel */ - if (fabs(t.alpha) > td->rotation_threshhold || t.zoom != 0) { - for (x = 0; x < td->width_dest; x++) { - for (y = 0; y < td->height_dest; y++) { - float x_d1 = (x - c_d_x); - float y_d1 = (y - c_d_y); - float x_s = zcos_a * x_d1 - + zsin_a * y_d1 + c_s_x -t.x; - float y_s = -zsin_a * x_d1 - + zcos_a * y_d1 + c_s_y -t.y; - unsigned char* dest = &Y_2[x + y * td->width_dest]; - interpolate(dest, x_s, y_s, Y_1, - td->width_src, td->height_src, - td->crop ? 16 : *dest,1,0); - } - } - }else { - /* no rotation, no zooming, just translation - *(also no interpolation, since no size change) - */ - int round_tx = myround(t.x); - int round_ty = myround(t.y); - for (x = 0; x < td->width_dest; x++) { - for (y = 0; y < td->height_dest; y++) { - short p = PIXEL(Y_1, x - round_tx, y - round_ty, - td->width_src, td->height_src, -1); - if (p == -1) { - if (td->crop == 1) - Y_2[x + y * td->width_dest] = 16; - } else { - Y_2[x + y * td->width_dest] = (unsigned char)p; - } - } - } - } - - /* Color channels */ - int ws2 = td->width_src/2; - int wd2 = td->width_dest/2; - int hs2 = td->height_src/2; - int hd2 = td->height_dest/2; - if (fabs(t.alpha) > td->rotation_threshhold || t.zoom != 0) { - for (x = 0; x < wd2; x++) { - for (y = 0; y < hd2; y++) { - float x_d1 = x - (c_d_x)/2; - float y_d1 = y - (c_d_y)/2; - float x_s = zcos_a * x_d1 - + zsin_a * y_d1 + (c_s_x -t.x)/2; - float y_s = -zsin_a * x_d1 - + zcos_a * y_d1 + (c_s_y -t.y)/2; - unsigned char* dest = &Cr_2[x + y * wd2]; - interpolate(dest, x_s, y_s, Cr_1, ws2, hs2, - td->crop ? 128 : *dest,1,0); - dest = &Cb_2[x + y * wd2]; - interpolate(dest, x_s, y_s, Cb_1, ws2, hs2, - td->crop ? 128 : *dest,1,0); - } - } - } else { // no rotation, no zoom, no interpolation, just translation - int round_tx2 = myround(t.x/2.0); - int round_ty2 = myround(t.y/2.0); - for (x = 0; x < wd2; x++) { - for (y = 0; y < hd2; y++) { - short cr = PIXEL(Cr_1, x - round_tx2, y - round_ty2, - wd2, hd2, -1); - short cb = PIXEL(Cb_1, x - round_tx2, y - round_ty2, - wd2, hd2, -1); - if (cr == -1) { - if (td->crop==1) { - Cr_2[x + y * wd2] = 128; - Cb_2[x + y * wd2] = 128; - } - } else { - Cr_2[x + y * wd2] = (unsigned char)cr; - Cb_2[x + y * wd2] = (unsigned char)cb; - } - } - } - } - return 1; -} - - -/** - * preprocess_transforms: does smoothing, relative to absolute conversion, - * and cropping of too large transforms. - * This is actually the core algorithm for canceling the jiggle in the - * movie. We perform a low-pass filter in terms of transformation size. - * This enables still camera movement, but in a smooth fashion. - * - * Parameters: - * td: transform private data structure - * Return value: - * 1 for success and 0 for failure - * Preconditions: - * None - * Side effects: - * td->trans will be modified - */ -int preprocess_transforms(TransformData* td) -{ - Transform* ts = td->trans; - int i; - - if (td->trans_len < 1) - return 0; - if (0) { - mlt_log_debug(NULL,"Preprocess transforms:"); - } - if (td->smoothing>0) { - /* smoothing */ - Transform* ts2 = malloc(sizeof(Transform) * td->trans_len); - memcpy(ts2, ts, sizeof(Transform) * td->trans_len); - - /* we will do a sliding average with minimal update - * \hat x_{n/2} = x_1+x_2 + .. + x_n - * \hat x_{n/2+1} = x_2+x_3 + .. + x_{n+1} = x_{n/2} - x_1 + x_{n+1} - * avg = \hat x / n - */ - int s = td->smoothing * 2 + 1; - Transform null = null_transform(); - /* avg is the average over [-smoothing, smoothing] transforms - around the current point */ - Transform avg; - /* avg2 is a sliding average over the filtered signal! (only to past) - * with smoothing * 10 horizont to kill offsets */ - Transform avg2 = null_transform(); - double tau = 1.0/(3 * s); - /* initialise sliding sum with hypothetic sum centered around - * -1st element. We have two choices: - * a) assume the camera is not moving at the beginning - * b) assume that the camera moves and we use the first transforms - */ - Transform s_sum = null; - for (i = 0; i < td->smoothing; i++){ - s_sum = add_transforms(&s_sum, i < td->trans_len ? &ts2[i]:&null); - } - mult_transform(&s_sum, 2); // choice b (comment out for choice a) - - for (i = 0; i < td->trans_len; i++) { - Transform* old = ((i - td->smoothing - 1) < 0) - ? &null : &ts2[(i - td->smoothing - 1)]; - Transform* new = ((i + td->smoothing) >= td->trans_len) - ? &null : &ts2[(i + td->smoothing)]; - s_sum = sub_transforms(&s_sum, old); - s_sum = add_transforms(&s_sum, new); - - avg = mult_transform(&s_sum, 1.0/s); - - /* lowpass filter: - * meaning high frequency must be transformed away - */ - ts[i] = sub_transforms(&ts2[i], &avg); - /* kill accumulating offset in the filtered signal*/ - avg2 = add_transforms_(mult_transform(&avg2, 1 - tau), - mult_transform(&ts[i], tau)); - ts[i] = sub_transforms(&ts[i], &avg2); - - if (0 /*verbose*/ ) { - mlt_log_warning(NULL,"s_sum: %5lf %5lf %5lf, ts: %5lf, %5lf, %5lf\n", - s_sum.x, s_sum.y, s_sum.alpha, - ts[i].x, ts[i].y, ts[i].alpha); - mlt_log_warning(NULL, - " avg: %5lf, %5lf, %5lf avg2: %5lf, %5lf, %5lf", - avg.x, avg.y, avg.alpha, - avg2.x, avg2.y, avg2.alpha); - } - } - free(ts2); - } - - - /* invert? */ - if (td->invert) { - for (i = 0; i < td->trans_len; i++) { - ts[i] = mult_transform(&ts[i], -1); - } - } - - /* relative to absolute */ - if (td->relative) { - Transform t = ts[0]; - for (i = 1; i < td->trans_len; i++) { - if (0/*verbose*/ ) { - mlt_log_warning(NULL, "shift: %5lf %5lf %lf \n", - t.x, t.y, t.alpha *180/M_PI); - } - ts[i] = add_transforms(&ts[i], &t); - t = ts[i]; - } - } - /* crop at maximal shift */ - if (td->maxshift != -1) - for (i = 0; i < td->trans_len; i++) { - ts[i].x = TC_CLAMP(ts[i].x, -td->maxshift, td->maxshift); - ts[i].y = TC_CLAMP(ts[i].y, -td->maxshift, td->maxshift); - } - if (td->maxangle != - 1.0) - for (i = 0; i < td->trans_len; i++) - ts[i].alpha = TC_CLAMP(ts[i].alpha, -td->maxangle, td->maxangle); - - /* Calc optimal zoom - * cheap algo is to only consider transformations - * uses cleaned max and min - */ - if (td->optzoom != 0 && td->trans_len > 1){ - Transform min_t, max_t; - cleanmaxmin_xy_transform(ts, td->trans_len, 10, &min_t, &max_t); - // the zoom value only for x - double zx = 2*TC_MAX(max_t.x,fabs(min_t.x))/td->width_src; - // the zoom value only for y - double zy = 2*TC_MAX(max_t.y,fabs(min_t.y))/td->height_src; - td->zoom += 100* TC_MAX(zx,zy); // use maximum - mlt_log_debug(NULL,"Final zoom: %lf\n", td->zoom); - } - - /* apply global zoom */ - if (td->zoom != 0){ - for (i = 0; i < td->trans_len; i++) - ts[i].zoom += td->zoom; - } - - return 1; -} - -/** - * transform_init: Initialize this instance of the module. See - * tcmodule-data.h for function details. - */ - -#if 0 - -static int transform_init(TCModuleInstance *self, uint32_t features) -{ - - TransformData* td = NULL; - TC_MODULE_SELF_CHECK(self, "init"); - TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features); - - td = tc_zalloc(sizeof(TransformData)); - if (td == NULL) { - tc_log_error(MOD_NAME, "init: out of memory!"); - return TC_ERROR; - } - self->userdata = td; - if (verbose) { - tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP); - } - - return T; -} -#endif - -/** - * transform_configure: Configure this instance of the module. See - * tcmodule-data.h for function details. - */ -int transform_configure(TransformData *self,int width,int height, mlt_image_format pixelformat, unsigned char* image ,Transform* tx,int trans_len) -{ - TransformData *td = self; - - /**** Initialise private data structure */ - - /* td->framesize = td->vob->im_v_width * - * MAX_PLANES * sizeof(char) * 2 * td->vob->im_v_height * 2; - */ - // rgb24 = w*h*3 , yuv420p = w* h* 3/2 - td->framesize_src = width*height*(pixelformat==mlt_image_rgb24 ? 3 : (3.0/2.0)); - td->src = malloc(td->framesize_src); /* FIXME */ - if (td->src == NULL) { - mlt_log_error(NULL,"tc_malloc failed\n"); - return -1; - } - - td->width_src = width; - td->height_src = height; - - /* Todo: in case we can scale the images, calc new size later */ - td->width_dest = width; - td->height_dest = height; - td->framesize_dest = td->framesize_src; - td->dest = 0; - - td->trans = tx; - td->trans_len = trans_len; - td->current_trans = 0; - td->warned_transform_end = 0; - - /* Options */ - // set from filter td->maxshift = -1; - // set from filter td->maxangle = -1; - - - // set from filter td->crop = 0; - // set from filter td->relative = 1; - // set from filter td->invert = 0; - // set from filter td->smoothing = 10; - - td->rotation_threshhold = 0.25/(180/M_PI); - - // set from filter td->zoom = 0; - // set from filter td->optzoom = 1; - // set from filter td->interpoltype = 2; // bi-linear - // set from filter td->sharpen = 0.8; - - td->interpoltype = TC_MIN(td->interpoltype,4); - if (1) { - mlt_log_debug(NULL, "Image Transformation/Stabilization Settings:\n"); - mlt_log_debug(NULL, " smoothing = %d\n", td->smoothing); - mlt_log_debug(NULL, " maxshift = %d\n", td->maxshift); - mlt_log_debug(NULL, " maxangle = %f\n", td->maxangle); - mlt_log_debug(NULL, " crop = %s\n", - td->crop ? "Black" : "Keep"); - mlt_log_debug(NULL, " relative = %s\n", - td->relative ? "True": "False"); - mlt_log_debug(NULL, " invert = %s\n", - td->invert ? "True" : "False"); - mlt_log_debug(NULL, " zoom = %f\n", td->zoom); - mlt_log_debug(NULL, " optzoom = %s\n", - td->optzoom ? "On" : "Off"); - mlt_log_debug(NULL, " interpol = %s\n", - interpoltypes[td->interpoltype]); - mlt_log_debug(NULL, " sharpen = %f\n", td->sharpen); - } - - if (td->maxshift > td->width_dest/2 - ) td->maxshift = td->width_dest/2; - if (td->maxshift > td->height_dest/2) - td->maxshift = td->height_dest/2; - - if (!preprocess_transforms(td)) { - mlt_log_error(NULL,"error while preprocessing transforms!"); - return -1; - } - - switch(td->interpoltype){ - case 0: interpolate = &interpolateZero; break; - case 1: interpolate = &interpolateLin; break; - case 2: interpolate = &interpolateBiLin; break; - case 3: interpolate = &interpolateSqr; break; - case 4: interpolate = &interpolateBiCub; break; - default: interpolate = &interpolateBiLin; - } - - return 0; -} - - -/** - * transform_filter_video: performs the transformation of frames - * See tcmodule-data.h for function details. - */ -int transform_filter_video(TransformData *self, - unsigned char *frame,mlt_image_format pixelformat) -{ - TransformData *td = self; - - - td->dest = frame; - memcpy(td->src, frame, td->framesize_src); - if (td->current_trans >= td->trans_len) { - td->current_trans = td->trans_len-1; - if(!td->warned_transform_end) - mlt_log_warning(NULL,"not enough transforms found, use last transformation!\n"); - td->warned_transform_end = 1; - } - - if (pixelformat == mlt_image_rgb24 ) { - transformRGB(td); - } else if (pixelformat == mlt_image_yuv420p) { - transformYUV(td); - } else { - mlt_log_error(NULL,"unsupported Codec: %i\n", pixelformat); - return 1; - } - td->current_trans++; - return 0; -} - - diff --git a/src/modules/videostab/transform_image.h b/src/modules/videostab/transform_image.h deleted file mode 100644 index a907968f9..000000000 --- a/src/modules/videostab/transform_image.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * filter_transform.c - * - * Copyright (C) Georg Martius - June 2007 - * georg dot martius at web dot de - * - * This file is part of transcode, a video stream processing tool - * - * transcode is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * transcode is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Typical call: - * transcode -J transform -i inp.mpeg -y xdiv,tcaud inp_stab.avi - */ - -#include "transform.h" - -#include -#include -#include "tlist.h" -#include - -#define DEFAULT_TRANS_FILE_NAME "transforms.dat" - -#define PIXEL(img, x, y, w, h, def) ((x) < 0 || (y) < 0) ? def \ - : (((x) >=w || (y) >= h) ? def : img[(x) + (y) * w]) -#define PIX(img, x, y, w, h) (img[(x) + (y) * w]) -#define PIXN(img, x, y, w, h,N,channel) (img[((x) + (y) * w)*N+channel]) -// gives Pixel in N-channel image. channel in {0..N-1} -#define PIXELN(img, x, y, w, h, N,channel , def) ((x) < 0 || (y) < 0) ? def \ - : (((x) >=w || (y) >= h) ? def : img[((x) + (y) * w)*N + channel]) - -typedef struct { - int framesize_src; // size of frame buffer in bytes (src) - int framesize_dest; // size of frame buffer in bytes (dest) - unsigned char* src; // copy of the current frame buffer - unsigned char* dest; // pointer to the current frame buffer (to overwrite) - - int pixelformat; - int width_src, height_src; - int width_dest, height_dest; - Transform* trans; // array of transformations - int current_trans; // index to current transformation - int trans_len; // length of trans array - short warned_transform_end; // whether we warned that there is no transform left - - /* Options */ - int maxshift; // maximum number of pixels we will shift - double maxangle; // maximum angle in rad - - /* whether to consider transforms as relative (to previous frame) - * or absolute transforms - */ - int relative; - /* number of frames (forward and backward) - * to use for smoothing transforms */ - int smoothing; - int crop; // 1: black bg, 0: keep border from last frame(s) - int invert; // 1: invert transforms, 0: nothing - /* constants */ - /* threshold below which no rotation is performed */ - double rotation_threshhold; - double zoom; // percentage to zoom: 0->no zooming 10:zoom in 10% - int optzoom; // 1: determine optimal zoom, 0: nothing - int interpoltype; // type of interpolation: 0->Zero,1->Lin,2->BiLin,3->Sqr - double sharpen; // amount of sharpening - - char conf_str[1024]; -} TransformData; - -/* forward declarations, please look below for documentation*/ -void interpolateBiLinBorder(unsigned char *rv, float x, float y, - unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); -void interpolateBiCub(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel); -void interpolateSqr(unsigned char *rv, float x, float y, - unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); -void interpolateBiLin(unsigned char *rv, float x, float y, - unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); -void interpolateLin(unsigned char *rv, float x, float y, - unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); -void interpolateZero(unsigned char *rv, float x, float y, - unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); -void interpolateN(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, - unsigned char N, unsigned char channel, unsigned char def); -int transformRGB(TransformData* td); -int transformYUV(TransformData* td); -int read_input_file(TransformData* td,tlist* list); -int preprocess_transforms(TransformData* td); - - -/** - * interpolate: general interpolation function pointer for one channel image data - * - * Parameters: - * rv: destination pixel (call by reference) - * x,y: the source coordinates in the image img. Note this - * are real-value coordinates, that's why we interpolate - * img: source image - * width,height: dimension of image - * def: default value if coordinates are out of range - * Return value: None - */ -/*void (*interpolate)(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, - unsigned char def) = 0; -*/ -/** interpolateBiLinBorder: bi-linear interpolation function that also works at the border. - This is used by many other interpolation methods at and outsize the border, see interpolate */ -int transform_configure(TransformData *self,int width,int height, mlt_image_format pixelformat, unsigned char* image,Transform* tx,int trans_len) ; - -int transform_filter_video(TransformData *self, - unsigned char *frame,mlt_image_format pixelformat); diff --git a/src/modules/vmfx/CMakeLists.txt b/src/modules/vmfx/CMakeLists.txt deleted file mode 100644 index f3a8b5241..000000000 --- a/src/modules/vmfx/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -add_library(mltvmfx MODULE - factory.c - filter_chroma_hold.c - filter_chroma.c - filter_mono.c - filter_shape.c - producer_pgm.c -) - -target_link_libraries(mltvmfx mlt) - -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltvmfx PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) - -install(TARGETS mltvmfx LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) - -install(FILES - filter_chroma_hold.yml - filter_chroma.yml - filter_mono.yml - filter_shape.yml - producer_pgm.yml - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/vmfx -) diff --git a/src/modules/vmfx/Makefile b/src/modules/vmfx/Makefile deleted file mode 100644 index 2343ec94a..000000000 --- a/src/modules/vmfx/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -CFLAGS += -I../.. - -LDFLAGS += -L../../framework -lmlt - -include ../../../config.mak - -TARGET = ../libmltvmfx$(LIBSUF) - -OBJS = factory.o \ - filter_chroma.o \ - filter_chroma_hold.o \ - filter_mono.o \ - filter_shape.o \ - producer_pgm.o - -SRCS := $(OBJS:.o=.c) - -all: $(TARGET) - -$(TARGET): $(OBJS) - $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) - -depend: $(SRCS) - $(CC) -MM $(CFLAGS) $^ 1>.depend - -distclean: clean - rm -f .depend - -clean: - rm -f $(OBJS) $(TARGET) - -install: all - install -m 755 $(TARGET) "$(DESTDIR)$(moduledir)" - install -d "$(DESTDIR)$(mltdatadir)/vmfx" - install -m 644 *.yml "$(DESTDIR)$(mltdatadir)/vmfx" - -ifneq ($(wildcard .depend),) -include .depend -endif diff --git a/src/modules/vmfx/factory.c b/src/modules/vmfx/factory.c deleted file mode 100644 index b10ef582b..000000000 --- a/src/modules/vmfx/factory.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * factory.c -- the factory method interfaces - * Copyright (C) 2005 Visual Media Fx Inc. - * Author: Charles Yates - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include - -extern mlt_filter filter_chroma_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -extern mlt_filter filter_chroma_hold_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -extern mlt_filter filter_mono_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 ); -extern mlt_producer producer_pgm_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/vmfx/%s", mlt_environment( "MLT_DATA" ), (char*) data ); - return mlt_properties_parse_yaml( file ); -} - -MLT_REPOSITORY -{ - MLT_REGISTER( filter_type, "chroma", filter_chroma_init ); - MLT_REGISTER( filter_type, "chroma_hold", filter_chroma_hold_init ); - MLT_REGISTER( filter_type, "threshold", filter_mono_init ); - MLT_REGISTER( filter_type, "shape", filter_shape_init ); - MLT_REGISTER( producer_type, "pgm", producer_pgm_init ); - - MLT_REGISTER_METADATA( filter_type, "chroma", metadata, "filter_chroma.yml" ); - MLT_REGISTER_METADATA( filter_type, "chroma_hold", metadata, "filter_chroma_hold.yml" ); - MLT_REGISTER_METADATA( filter_type, "threshold", metadata, "filter_mono.yml" ); - MLT_REGISTER_METADATA( filter_type, "shape", metadata, "filter_shape.yml" ); - MLT_REGISTER_METADATA( producer_type, "pgm", metadata, "producer_pgm.yml" ); -} diff --git a/src/modules/vorbis/CMakeLists.txt b/src/modules/vorbis/CMakeLists.txt index 806383069..2c4a459d3 100644 --- a/src/modules/vorbis/CMakeLists.txt +++ b/src/modules/vorbis/CMakeLists.txt @@ -1,9 +1,11 @@ add_library(mltvorbis MODULE factory.c producer_vorbis.c) -target_link_libraries(mltvorbis mlt PkgConfig::vorbis PkgConfig::vorbisfile) -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltvorbis PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +target_compile_options(mltvorbis PRIVATE ${MLT_COMPILE_OPTIONS}) -install(TARGETS mltvorbis LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +target_link_libraries(mltvorbis PRIVATE mlt PkgConfig::vorbis PkgConfig::vorbisfile) -install(FILES producer_vorbis.yml DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/vorbis) +set_target_properties(mltvorbis PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") + +install(TARGETS mltvorbis LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) + +install(FILES producer_vorbis.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/vorbis) diff --git a/src/modules/vorbis/factory.c b/src/modules/vorbis/factory.c index 112d66b95..eb90a87db 100644 --- a/src/modules/vorbis/factory.c +++ b/src/modules/vorbis/factory.c @@ -32,6 +32,6 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( producer_type, "vorbis", producer_vorbis_init ); - MLT_REGISTER_METADATA( producer_type, "vorbis", metadata, "producer_vorbis.yml" ); + MLT_REGISTER( mlt_service_producer_type, "vorbis", producer_vorbis_init ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "vorbis", metadata, "producer_vorbis.yml" ); } diff --git a/src/modules/xine/CMakeLists.txt b/src/modules/xine/CMakeLists.txt index 92a439940..478d68800 100644 --- a/src/modules/xine/CMakeLists.txt +++ b/src/modules/xine/CMakeLists.txt @@ -5,21 +5,39 @@ add_library(mltxine MODULE filter_deinterlace.c ) -target_link_libraries(mltxine mlt) +target_compile_options(mltxine PRIVATE ${MLT_COMPILE_OPTIONS}) + +target_link_libraries(mltxine PRIVATE mlt) set_target_properties(mltxine PROPERTIES POSITION_INDEPENDENT_CODE ON) target_compile_definitions(mltxine PRIVATE PIC) -if(X86_64) +if(CPU_MMX) + target_compile_definitions(mltxine PRIVATE USE_MMX) target_sources(mltxine PRIVATE cpu_accel.c) - if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") + if(CMAKE_C_COMPILER_ID MATCHES "GNU") # avoid crash in yadif filter_line_sse2 target_compile_options(mltxine PRIVATE -fno-tree-dominator-opts -fno-tree-pre) endif() endif() -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltxine PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +if(CPU_SSE) + target_compile_definitions(mltxine PRIVATE USE_SSE) +endif() + +if(CPU_SSE2) + target_compile_definitions(mltxine PRIVATE USE_SSE2) +endif() + +if(CPU_X86_32) + target_compile_definitions(mltxine PRIVATE ARCH_X86) +endif() + +if(CPU_X86_64) + target_compile_definitions(mltxine PRIVATE ARCH_X86_64) +endif() + +set_target_properties(mltxine PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") -install(TARGETS mltxine LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +install(TARGETS mltxine LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) diff --git a/src/modules/xine/factory.c b/src/modules/xine/factory.c index 12e661a1c..4571f397b 100644 --- a/src/modules/xine/factory.c +++ b/src/modules/xine/factory.c @@ -24,5 +24,5 @@ extern mlt_filter filter_deinterlace_init( mlt_profile profile, mlt_service_type MLT_REPOSITORY { - MLT_REGISTER( filter_type, "deinterlace", filter_deinterlace_init ); + MLT_REGISTER( mlt_service_filter_type, "deinterlace", filter_deinterlace_init ); } diff --git a/src/modules/xml/CMakeLists.txt b/src/modules/xml/CMakeLists.txt index c8153edca..96af855cc 100644 --- a/src/modules/xml/CMakeLists.txt +++ b/src/modules/xml/CMakeLists.txt @@ -5,12 +5,13 @@ add_library(mltxml MODULE producer_xml.c ) -target_link_libraries(mltxml mlt Threads::Threads PkgConfig::xml) +target_compile_options(mltxml PRIVATE ${MLT_COMPILE_OPTIONS}) -# Create module in parent directory, for the benefit of "source setenv". -set_target_properties(mltxml PROPERTIES LIBRARY_OUTPUT_DIRECTORY ..) +target_link_libraries(mltxml PRIVATE mlt Threads::Threads PkgConfig::xml) -install(TARGETS mltxml LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mlt) +set_target_properties(mltxml PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") + +install(TARGETS mltxml LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES consumer_xml.yml @@ -18,5 +19,5 @@ install(FILES producer_xml-string.yml producer_xml.yml mlt-xml.dtd - DESTINATION ${CMAKE_INSTALL_DATADIR}/mlt/xml + DESTINATION ${MLT_INSTALL_DATA_DIR}/xml ) diff --git a/src/modules/xml/consumer_xml.c b/src/modules/xml/consumer_xml.c index 07434a903..694fda413 100644 --- a/src/modules/xml/consumer_xml.c +++ b/src/modules/xml/consumer_xml.c @@ -1,6 +1,6 @@ /* * consumer_xml.c -- a libxml2 serialiser of mlt service networks - * Copyright (C) 2003-2020 Meltytech, LLC + * Copyright (C) 2003-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 @@ -44,6 +44,8 @@ struct serialise_context_s int tractor_count; int filter_count; int transition_count; + int chain_count; + int link_count; int pass; mlt_properties hide_map; char *root; @@ -72,7 +74,9 @@ typedef enum xml_playlist, xml_tractor, xml_filter, - xml_transition + xml_transition, + xml_chain, + xml_link, } xml_type; @@ -123,6 +127,12 @@ static char *xml_get_id( serialise_context context, mlt_service service, xml_typ case xml_transition: sprintf( temp, "transition%d", context->transition_count ++ ); break; + case xml_chain: + sprintf( temp, "chain%d", context->chain_count ++ ); + break; + case xml_link: + sprintf( temp, "link%d", context->link_count ++ ); + break; case xml_existing: // Never gets here break; @@ -525,8 +535,6 @@ static void serialise_tractor( serialise_context context, mlt_service service, x xmlNewProp( child, _x("id"), _x(id) ); if ( mlt_properties_get( properties, "title" ) ) xmlNewProp( child, _x("title"), _x(mlt_properties_get( properties, "title" )) ); - if ( mlt_properties_get( properties, "global_feed" ) ) - xmlNewProp( child, _x("global_feed"), _x(mlt_properties_get( properties, "global_feed" )) ); if ( mlt_properties_get_position( properties, "in" ) >= 0 ) xmlNewProp( child, _x("in"), _x(mlt_properties_get_time( properties, "in", context->time_format )) ); if ( mlt_properties_get_position( properties, "out" ) >= 0 ) @@ -606,6 +614,74 @@ static void serialise_transition( serialise_context context, mlt_service service } } +static void serialise_link( serialise_context context, mlt_service service, xmlNode *node ) +{ + xmlNode *child = node; + mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); + + if ( context->pass == 0 ) + { + // Get a new id - if already allocated, do nothing + char *id = xml_get_id( context, service, xml_link ); + if ( id == NULL ) + return; + + child = xmlNewChild( node, NULL, _x("link"), NULL ); + + // Set the id + xmlNewProp( child, _x("id"), _x(id) ); + if ( mlt_properties_get( properties, "title" ) ) + xmlNewProp( child, _x("title"), _x(mlt_properties_get( properties, "title" )) ); + if ( mlt_properties_get_position( properties, "in" ) ) + xmlNewProp( child, _x("in"), _x( mlt_properties_get_time( properties, "in", context->time_format ) ) ); + if ( mlt_properties_get_position( properties, "out" ) ) + xmlNewProp( child, _x("out"), _x( mlt_properties_get_time( properties, "out", context->time_format ) ) ); + + serialise_properties( context, properties, child ); + serialise_service_filters( context, service, child ); + } +} + +static void serialise_chain( serialise_context context, mlt_service service, xmlNode *node ) +{ + int i = 0; + xmlNode *child = node; + mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); + + if ( context->pass == 0 ) + { + // Get a new id - if already allocated, do nothing + char *id = xml_get_id( context, service, xml_chain ); + if ( id == NULL ) + return; + + child = xmlNewChild( node, NULL, _x("chain"), NULL ); + + // Set the id + xmlNewProp( child, _x("id"), _x(id) ); + if ( mlt_properties_get( properties, "title" ) ) + xmlNewProp( child, _x("title"), _x(mlt_properties_get( properties, "title" )) ); + if ( mlt_properties_get_position( properties, "in" ) ) + xmlNewProp( child, _x("in"), _x( mlt_properties_get_time( properties, "in", context->time_format ) ) ); + if ( mlt_properties_get_position( properties, "out" ) ) + xmlNewProp( child, _x("out"), _x( mlt_properties_get_time( properties, "out", context->time_format ) ) ); + + serialise_properties( context, properties, child ); + + // Serialize links + for ( i = 0; i < mlt_chain_link_count( MLT_CHAIN( service ) ); i++ ) + { + mlt_link link = mlt_chain_link( MLT_CHAIN( service ), i ); + if ( link ) + { + serialise_link( context, MLT_LINK_SERVICE(link), child ); + } + } + + serialise_service_filters( context, service, child ); + } +} + static void serialise_service( serialise_context context, mlt_service service, xmlNode *node ) { // Iterate over consumer/producer connections @@ -664,6 +740,15 @@ static void serialise_service( serialise_context context, mlt_service service, x break; } + // Treat it as a normal chain + else if ( mlt_properties_get_int( properties, "_original_type" ) == mlt_service_chain_type ) + { + serialise_chain( context, service, node ); + mlt_properties_set( properties, "mlt_type", "chain" ); + if ( mlt_properties_get( properties, "xml" ) != NULL ) + break; + } + // Treat it as a normal producer else { @@ -673,6 +758,13 @@ static void serialise_service( serialise_context context, mlt_service service, x } } + // Tell about a chain + else if ( strcmp( mlt_type, "chain" ) == 0 ) + { + serialise_chain( context, service, node ); + break; + } + // Tell about a filter else if ( strcmp( mlt_type, "filter" ) == 0 ) { @@ -768,7 +860,6 @@ xmlDocPtr xml_make_doc( mlt_consumer consumer, mlt_service service ) // Assign a title property if ( mlt_properties_get( properties, "title" ) != NULL ) xmlNewProp( root, _x("title"), _x(mlt_properties_get( properties, "title" )) ); - mlt_properties_set_int( properties, "global_feed", 1 ); // Add a profile child element if ( profile ) @@ -807,6 +898,7 @@ xmlDocPtr xml_make_doc( mlt_consumer consumer, mlt_service service ) context->hide_map = mlt_properties_new(); // Ensure producer is a framework producer + mlt_properties_set_int( properties, "_original_type", mlt_service_identify( service ) ); mlt_properties_set( MLT_SERVICE_PROPERTIES( service ), "mlt_type", "mlt_producer" ); // In pass one, we serialise the end producers and playlists, @@ -992,7 +1084,7 @@ static void *consumer_thread( void *arg ) mlt_frame_get_audio( frame, (void**) &buffer, &aformat, &frequency, &channels, &samples ); // Close the frame - mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + mlt_events_fire( properties, "consumer-frame-show", mlt_event_data_from_frame(frame) ); mlt_frame_close( frame ); } } diff --git a/src/modules/xml/consumer_xml.yml b/src/modules/xml/consumer_xml.yml index c9ad925cf..1f4b0461b 100644 --- a/src/modules/xml/consumer_xml.yml +++ b/src/modules/xml/consumer_xml.yml @@ -52,7 +52,7 @@ parameters: description: > Without this option, the XML consumer does not process any frames and simply serializes the service network. However, some filters (.e.g, - videostab) require two passes where the first pass performs some + vid.stab) require two passes where the first pass performs some analysis and stores the result in a property. Therefore, set this property to 1 (true) to cause the consumer to process all frames before serializing to XML. diff --git a/src/modules/xml/factory.c b/src/modules/xml/factory.c index 03d379654..ac07441b2 100644 --- a/src/modules/xml/factory.c +++ b/src/modules/xml/factory.c @@ -33,13 +33,13 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( consumer_type, "xml", consumer_xml_init ); - MLT_REGISTER( producer_type, "xml", producer_xml_init ); - MLT_REGISTER( producer_type, "xml-string", producer_xml_init ); - MLT_REGISTER( producer_type, "xml-nogl", producer_xml_init ); + MLT_REGISTER( mlt_service_consumer_type, "xml", consumer_xml_init ); + MLT_REGISTER( mlt_service_producer_type, "xml", producer_xml_init ); + MLT_REGISTER( mlt_service_producer_type, "xml-string", producer_xml_init ); + MLT_REGISTER( mlt_service_producer_type, "xml-nogl", producer_xml_init ); - MLT_REGISTER_METADATA( consumer_type, "xml", metadata, "consumer_xml.yml" ); - MLT_REGISTER_METADATA( producer_type, "xml", metadata, "producer_xml.yml" ); - MLT_REGISTER_METADATA( producer_type, "xml-string", metadata, "producer_xml-string.yml" ); - MLT_REGISTER_METADATA( producer_type, "xml-nogl", metadata, "producer_xml-nogl.yml" ); + MLT_REGISTER_METADATA( mlt_service_consumer_type, "xml", metadata, "consumer_xml.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "xml", metadata, "producer_xml.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "xml-string", metadata, "producer_xml-string.yml" ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "xml-nogl", metadata, "producer_xml-nogl.yml" ); } diff --git a/src/modules/xml/mlt-xml.dtd b/src/modules/xml/mlt-xml.dtd index c4473e820..67fa85409 100644 --- a/src/modules/xml/mlt-xml.dtd +++ b/src/modules/xml/mlt-xml.dtd @@ -1,8 +1,8 @@ - + - + + + + + - + - + - + - + producer_map, mlt_properties_get( properties, "id" ), service, 0, NULL, NULL ); @@ -571,6 +571,200 @@ static void on_end_playlist( deserialise_context context, const xmlChar *name ) } } +static void on_start_chain( deserialise_context context, const xmlChar *name, const xmlChar **atts) +{ + mlt_chain chain = mlt_chain_init( context->profile ); + mlt_service service = MLT_CHAIN_SERVICE( chain ); + mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); + + track_service( context->destructors, service, (mlt_destructor) mlt_chain_close ); + + for ( ; atts != NULL && *atts != NULL; atts += 2 ) + { + mlt_properties_set_string( properties, (const char*) atts[0], atts[1] == NULL ? "" : (const char*) atts[1] ); + + // Out will be overwritten later as we append, so we need to save it + if ( xmlStrcmp( atts[ 0 ], _x("out") ) == 0 ) + mlt_properties_set_string( properties, "_xml.out", ( const char* )atts[ 1 ] ); + } + + if ( mlt_properties_get( properties, "id" ) != NULL ) + mlt_properties_set_data( context->producer_map, mlt_properties_get( properties, "id" ), service, 0, NULL, NULL ); + + context_push_service( context, service, mlt_chain_type ); +} + +static void on_end_chain( deserialise_context context, const xmlChar *name ) +{ + // Get the chain from the stack + enum service_type type; + mlt_service service = context_pop_service( context, &type ); + + if ( service != NULL && type == mlt_chain_type ) + { + mlt_chain chain = MLT_CHAIN( service ); + mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); + mlt_position in = -1; + mlt_position out = -1; + mlt_producer source = NULL; + + qualify_property( context, properties, "resource" ); + char *resource = mlt_properties_get( properties, "resource" ); + + // Let Kino-SMIL src be a synonym for resource + if ( resource == NULL ) + { + qualify_property( context, properties, "src" ); + resource = mlt_properties_get( properties, "src" ); + } + + // Instantiate the producer + if ( mlt_properties_get( properties, "mlt_service" ) != NULL ) + { + char *service_name = trim( mlt_properties_get( properties, "mlt_service" ) ); + if ( resource ) + { + // If a document was saved as +INVALID.txt (see below), then ignore the mlt_service and + // try to load it just from the resource. This is an attempt to recover the failed + // producer in case, for example, a file returns. + if (!strcmp("qtext", service_name)) { + const char *text = mlt_properties_get( properties, "text" ); + if (text && !strcmp("INVALID", text)) { + service_name = NULL; + } + } else if (!strcmp("pango", service_name)) { + const char *markup = mlt_properties_get( properties, "markup" ); + if (markup && !strcmp("INVALID", markup)) { + service_name = NULL; + } + } + if (service_name) { + char *temp = calloc( 1, strlen( service_name ) + strlen( resource ) + 2 ); + strcat( temp, service_name ); + strcat( temp, ":" ); + strcat( temp, resource ); + source = mlt_factory_producer( context->profile, NULL, temp ); + free( temp ); + } + } + else + { + source = mlt_factory_producer( context->profile, NULL, service_name ); + } + } + + // Just in case the plugin requested doesn't exist... + if ( !source && resource ) + source = mlt_factory_producer( context->profile, NULL, resource ); + if ( !source ) { + mlt_log_error( NULL, "[producer_xml] failed to load producer \"%s\"\n", resource ); + source = mlt_factory_producer( context->profile, NULL, "+INVALID.txt" ); + if (source) { + // Save the original mlt_service for the consumer to serialize it as original. + mlt_properties_set_string( properties, "_xml_mlt_service", + mlt_properties_get( properties, "mlt_service" ) ); + } + } + if ( !source ) + source = mlt_factory_producer( context->profile, NULL, "colour:red" ); + // Propogate properties to the source + mlt_properties_inherit( MLT_PRODUCER_PROPERTIES( source ), properties ); + // Add the source producer to the chain + mlt_chain_set_source( chain, source ); + + // See if the chain should be added to a playlist or multitrack + if ( mlt_properties_get( properties, "in" ) ) + in = mlt_properties_get_position( properties, "in" ); + if ( mlt_properties_get( properties, "out" ) ) + out = mlt_properties_get_position( properties, "out" ); + if ( add_producer( context, service, in, out ) == 0 ) + context_push_service( context, service, type ); + } + else + { + mlt_log_error( NULL, "[producer_xml] Invalid state of chain end %d\n", type ); + } +} + +static void on_start_link( deserialise_context context, const xmlChar *name, const xmlChar **atts) +{ + // Store properties until the service type is known + mlt_service service = calloc( 1, sizeof( struct mlt_service_s ) ); + mlt_service_init( service, NULL ); + mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); + context_push_service( context, service, mlt_link_type ); + + for ( ; atts != NULL && *atts != NULL; atts += 2 ) + mlt_properties_set_string( properties, (const char*) atts[0], atts[1] == NULL ? "" : (const char*) atts[1] ); +} + +static void on_end_link( deserialise_context context, const xmlChar *name ) +{ + enum service_type type; + mlt_service service = context_pop_service( context, &type ); + mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); + + enum service_type parent_type = mlt_invalid_type; + mlt_service parent = context_pop_service( context, &parent_type ); + + if ( service != NULL && type == mlt_link_type ) + { + char *id = trim( mlt_properties_get( properties, "mlt_service" ) ); + mlt_service link = MLT_SERVICE( mlt_factory_link( id, NULL ) ); + mlt_properties link_props = MLT_SERVICE_PROPERTIES( link ); + + if ( !link ) + { + mlt_log_error( NULL, "[producer_xml] failed to load link \"%s\"\n", id ); + if ( parent ) + context_push_service( context, parent, parent_type ); + mlt_service_close( service ); + free( service ); + return; + } + + track_service( context->destructors, link, (mlt_destructor) mlt_link_close ); + mlt_properties_set_lcnumeric( MLT_SERVICE_PROPERTIES( link ), context->lc_numeric ); + + // Do not let XML overwrite these important properties set by mlt_factory. + mlt_properties_set_string( properties, "mlt_type", NULL ); + mlt_properties_set_string( properties, "mlt_service", NULL ); + + // Propagate the properties + mlt_properties_inherit( link_props, properties ); + + // Attach the link to the chain + if ( parent != NULL ) + { + if ( parent_type == mlt_chain_type ) + { + mlt_chain_attach( MLT_CHAIN( parent ), MLT_LINK( link ) ); + } + else + { + mlt_log_error( NULL, "[producer_xml] link can only be added to a chain...\n" ); + } + + // Put the parent back on the stack + context_push_service( context, parent, parent_type ); + } + else + { + mlt_log_error( NULL, "[producer_xml] link closed with invalid parent...\n" ); + } + } + else + { + mlt_log_error( NULL, "[producer_xml] Invalid top of stack on link close\n" ); + } + + if ( service ) + { + mlt_service_close( service ); + free(service); + } +} + static void on_start_producer( deserialise_context context, const xmlChar *name, const xmlChar **atts) { // use a dummy service to hold properties to allow arbitrary nesting @@ -1412,6 +1606,10 @@ static void on_start_element( void *ctx, const xmlChar *name, const xmlChar **at on_start_filter( context, name, atts ); else if ( xmlStrcmp( name, _x("transition") ) == 0 ) on_start_transition( context, name, atts ); + else if ( xmlStrcmp( name, _x("chain") ) == 0 ) + on_start_chain( context, name, atts ); + else if ( xmlStrcmp( name, _x("link") ) == 0 ) + on_start_link( context, name, atts ); else if ( xmlStrcmp( name, _x("property") ) == 0 ) on_start_property( context, name, atts ); else if ( xmlStrcmp( name, _x("consumer") ) == 0 ) @@ -1453,6 +1651,10 @@ static void on_end_element( void *ctx, const xmlChar *name ) on_end_filter( context, name ); else if ( xmlStrcmp( name, _x("transition") ) == 0 ) on_end_transition( context, name ); + else if ( xmlStrcmp( name, _x("chain") ) == 0 ) + on_end_chain( context, name ); + else if ( xmlStrcmp( name, _x("link") ) == 0 ) + on_end_link( context, name ); else if ( xmlStrcmp( name, _x("consumer") ) == 0 ) on_end_consumer( context, name ); @@ -1956,9 +2158,9 @@ mlt_producer producer_xml_init( mlt_profile profile, mlt_service_type servtype, if ( well_formed && service != NULL ) { // Verify it is a producer service (mlt_type="mlt_producer") - // (producer, playlist, multitrack) + // (producer, chain, playlist, multitrack) char *type = mlt_properties_get( MLT_SERVICE_PROPERTIES( service ), "mlt_type" ); - if ( type == NULL || ( strcmp( type, "mlt_producer" ) != 0 && strcmp( type, "producer" ) != 0 ) ) + if ( type == NULL || ( strcmp( type, "mlt_producer" ) != 0 && strcmp( type, "producer" ) != 0 && strcmp( type, "chain" ) != 0 ) ) service = NULL; } @@ -2002,9 +2204,9 @@ mlt_producer producer_xml_init( mlt_profile profile, mlt_service_type servtype, { // Now assign additional properties if ( is_filename && ( - mlt_service_identify( service ) == tractor_type || - mlt_service_identify( service ) == playlist_type || - mlt_service_identify( service ) == multitrack_type ) ) + mlt_service_identify( service ) == mlt_service_tractor_type || + mlt_service_identify( service ) == mlt_service_playlist_type || + mlt_service_identify( service ) == mlt_service_multitrack_type ) ) { mlt_properties_set_int( properties, "_original_type", mlt_service_identify( service ) ); diff --git a/src/swig/csharp/CMakeLists.txt b/src/swig/csharp/CMakeLists.txt index 2016e8aa6..b927e0b19 100644 --- a/src/swig/csharp/CMakeLists.txt +++ b/src/swig/csharp/CMakeLists.txt @@ -1,7 +1,8 @@ set_source_files_properties(../mlt.i PROPERTIES USE_TARGET_INCLUDE_DIRECTORIES ON CPLUSPLUS ON) swig_add_library(mltsharp LANGUAGE csharp OUTPUT_DIR src_swig SOURCES ../mlt.i) -target_link_libraries(mltsharp mlt mlt++) +target_compile_options(mltsharp PRIVATE ${MLT_COMPILE_OPTIONS}) +target_link_libraries(mltsharp PRIVATE mlt mlt++) add_custom_command(TARGET mltsharp POST_BUILD COMMAND mcs -out:mlt-sharp.dll -target:library src_swig/*.cs diff --git a/src/swig/java/CMakeLists.txt b/src/swig/java/CMakeLists.txt index 226f59739..ef6efb36f 100644 --- a/src/swig/java/CMakeLists.txt +++ b/src/swig/java/CMakeLists.txt @@ -1,7 +1,8 @@ set_source_files_properties(../mlt.i PROPERTIES USE_TARGET_INCLUDE_DIRECTORIES ON CPLUSPLUS ON) swig_add_library(mltjava LANGUAGE java OUTPUT_DIR src_swig SOURCES ../mlt.i) -target_link_libraries(mltjava mlt mlt++) +target_compile_options(mltjava PRIVATE ${MLT_COMPILE_OPTIONS}) +target_link_libraries(mltjava PRIVATE mlt mlt++) target_include_directories(mltjava PRIVATE ${JNI_INCLUDE_DIRS}) set_target_properties(mltjava PROPERTIES OUTPUT_NAME "mlt_java") diff --git a/src/swig/lua/CMakeLists.txt b/src/swig/lua/CMakeLists.txt index 2b9470695..e2e3372ed 100644 --- a/src/swig/lua/CMakeLists.txt +++ b/src/swig/lua/CMakeLists.txt @@ -1,6 +1,7 @@ set_source_files_properties(../mlt.i PROPERTIES USE_TARGET_INCLUDE_DIRECTORIES ON CPLUSPLUS ON) swig_add_library(mltlua LANGUAGE lua SOURCES ../mlt.i) -target_link_libraries(mltlua mlt mlt++) +target_compile_options(mltlua PRIVATE ${MLT_COMPILE_OPTIONS}) +target_link_libraries(mltlua PRIVATE mlt mlt++) target_include_directories(mltlua PRIVATE ${LUA_INCLUDE_DIR}) set_target_properties(mltlua PROPERTIES OUTPUT_NAME "mlt") diff --git a/src/swig/mlt.i b/src/swig/mlt.i index 58b3d62e2..8b5046425 100644 --- a/src/swig/mlt.i +++ b/src/swig/mlt.i @@ -1,7 +1,6 @@ /** * mlt.i - Swig Bindings for mlt++ - * Copyright (C) 2004-2015 Meltytech, LLC - * Author: Charles Yates + * Copyright (C) 2004-2021 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 @@ -92,7 +91,6 @@ void mlt_log_set_level( int ); %include %include %include -%include %include %include %include @@ -160,7 +158,7 @@ void markRubyListener( void* p ) o->mark( ); } -static void on_playlist_next( mlt_properties owner, void *object, int i ); +static void on_playlist_next( mlt_properties owner, void *object, mlt_event_data ); class PlaylistNextListener : RubyListener { @@ -168,8 +166,8 @@ class PlaylistNextListener : RubyListener Mlt::Event *event; public: - PlaylistNextListener( Mlt::Properties *properties, VALUE proc ) - : RubyListener( proc ) + PlaylistNextListener( Mlt::Properties *properties, VALUE callback ) + : RubyListener( callback ) { event = properties->listen( "playlist-next", this, ( mlt_listener )on_playlist_next ); } @@ -179,17 +177,18 @@ class PlaylistNextListener : RubyListener delete event; } - void yield( int i ) + void yield(const Mlt::EventData& eventData) { ID method = rb_intern( "call" ); - rb_funcall( callback, method, 1, INT2FIX( i ) ); + rb_funcall( callback, method, 1, INT2FIX( eventData.to_int() ) ); } }; -static void on_playlist_next( mlt_properties owner, void *object, int i ) +static void on_playlist_next( mlt_properties owner, void *object, mlt_event_data event_data ) { PlaylistNextListener *o = static_cast< PlaylistNextListener * >( object ); - o->yield( i ); + Mlt::EventData data(event_data); + o->yield(data); } %} diff --git a/src/swig/nodejs/CMakeLists.txt b/src/swig/nodejs/CMakeLists.txt index f5e8c1616..9ae1a2395 100644 --- a/src/swig/nodejs/CMakeLists.txt +++ b/src/swig/nodejs/CMakeLists.txt @@ -1,7 +1,8 @@ set_source_files_properties(../mlt.i PROPERTIES USE_TARGET_INCLUDE_DIRECTORIES ON CPLUSPLUS ON) swig_add_library(mltnodejs LANGUAGE javascript SOURCES ../mlt.i) -target_link_libraries(mltnodejs mlt mlt++) +target_compile_options(mltnodejs PRIVATE ${MLT_COMPILE_OPTIONS}) +target_link_libraries(mltnodejs PRIVATE mlt mlt++) target_include_directories(mltnodejs PRIVATE ${NODEJS_INCLUDE_DIRS}) set_target_properties(mltnodejs PROPERTIES diff --git a/src/swig/perl/CMakeLists.txt b/src/swig/perl/CMakeLists.txt index 8d007ac15..6ac2672a2 100644 --- a/src/swig/perl/CMakeLists.txt +++ b/src/swig/perl/CMakeLists.txt @@ -1,7 +1,8 @@ set_source_files_properties(../mlt.i PROPERTIES USE_TARGET_INCLUDE_DIRECTORIES ON CPLUSPLUS ON) swig_add_library(mltperl LANGUAGE perl SOURCES ../mlt.i) -target_link_libraries(mltperl mlt mlt++) +target_compile_options(mltperl PRIVATE ${MLT_COMPILE_OPTIONS}) +target_link_libraries(mltperl PRIVATE mlt mlt++) target_include_directories(mltperl PRIVATE ${PERL_INCLUDE_PATH}) set_target_properties(mltperl PROPERTIES OUTPUT_NAME "mlt") diff --git a/src/swig/php/CMakeLists.txt b/src/swig/php/CMakeLists.txt index 6d89987e6..8005022f3 100644 --- a/src/swig/php/CMakeLists.txt +++ b/src/swig/php/CMakeLists.txt @@ -1,7 +1,8 @@ set_source_files_properties(../mlt.i PROPERTIES USE_TARGET_INCLUDE_DIRECTORIES ON CPLUSPLUS ON) swig_add_library(mltphp LANGUAGE php SOURCES ../mlt.i) -target_link_libraries(mltphp mlt mlt++ PHP::Extension) +target_compile_options(mltphp PRIVATE ${MLT_COMPILE_OPTIONS}) +target_link_libraries(mltphp PRIVATE mlt mlt++ PHP::Extension) set_target_properties(mltphp PROPERTIES OUTPUT_NAME "mlt") if(PHP_EXTENSION_DIR) diff --git a/src/swig/python/CMakeLists.txt b/src/swig/python/CMakeLists.txt index 25a120a66..321fa011c 100644 --- a/src/swig/python/CMakeLists.txt +++ b/src/swig/python/CMakeLists.txt @@ -1,10 +1,14 @@ set_source_files_properties(../mlt.i PROPERTIES USE_TARGET_INCLUDE_DIRECTORIES ON CPLUSPLUS ON) swig_add_library(mltpython LANGUAGE python SOURCES ../mlt.i) -target_link_libraries(mltpython mlt mlt++ Python3::Module) -set_target_properties(mltpython PROPERTIES PREFIX "_" OUTPUT_NAME "mlt") +target_compile_options(mltpython PRIVATE ${MLT_COMPILE_OPTIONS}) +target_link_libraries(mltpython PRIVATE mlt mlt++ Python3::Module) +set_target_properties(mltpython PROPERTIES PREFIX "_" OUTPUT_NAME "mlt${MLT_VERSION_MAJOR}") string(REGEX MATCH "[lL]ib.*" PYTHON_MODULE_INSTALL_DIR ${Python3_SITELIB}) install(TARGETS mltpython DESTINATION ${PYTHON_MODULE_INSTALL_DIR}) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mlt.py DESTINATION ${PYTHON_MODULE_INSTALL_DIR}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mlt.py + DESTINATION ${PYTHON_MODULE_INSTALL_DIR} + RENAME mlt${MLT_VERSION_MAJOR}.py +) diff --git a/src/swig/ruby/CMakeLists.txt b/src/swig/ruby/CMakeLists.txt index 1cbcb25a2..ddfdd6b28 100644 --- a/src/swig/ruby/CMakeLists.txt +++ b/src/swig/ruby/CMakeLists.txt @@ -1,6 +1,7 @@ set_source_files_properties(../mlt.i PROPERTIES USE_TARGET_INCLUDE_DIRECTORIES ON CPLUSPLUS ON) swig_add_library(mltruby LANGUAGE ruby SOURCES ../mlt.i) +target_compile_options(mltruby PRIVATE ${MLT_COMPILE_OPTIONS}) target_link_libraries(mltruby PRIVATE mlt++) target_include_directories(mltruby PRIVATE ${RUBY_INCLUDE_DIRS}) set_target_properties(mltruby PROPERTIES OUTPUT_NAME "mlt") diff --git a/src/swig/ruby/play.rb b/src/swig/ruby/play.rb index fda7d5b0f..9f1c0d2c8 100755 --- a/src/swig/ruby/play.rb +++ b/src/swig/ruby/play.rb @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # Import required modules -require 'mlt' +require './mlt' # Create the mlt system Mlt::Factory::init diff --git a/src/swig/ruby/playlist.rb b/src/swig/ruby/playlist.rb index 99bb341f8..7b794e36f 100755 --- a/src/swig/ruby/playlist.rb +++ b/src/swig/ruby/playlist.rb @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # Import required modules -require 'mlt' +require './mlt' # Create the mlt system Mlt::Factory::init @@ -29,7 +29,7 @@ pls.append(producer2) # Create the consumer -consumer = Mlt::Consumer.new( profile, "sdl" ) +consumer = Mlt::Consumer.new( profile, "sdl2" ) raise "Unable to open sdl consumer" if !consumer.is_valid # Turn off the default rescaling @@ -55,6 +55,8 @@ # Wait until the user stops the consumer consumer.wait_for( event ) +puts "Done and closing" + # Clean up consumer consumer.stop diff --git a/src/swig/ruby/thumbs.rb b/src/swig/ruby/thumbs.rb index 1b132e882..51293a085 100755 --- a/src/swig/ruby/thumbs.rb +++ b/src/swig/ruby/thumbs.rb @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # Required modules -require 'mlt' +require './mlt' # Create the mlt system Mlt::Factory::init diff --git a/src/swig/tcl/CMakeLists.txt b/src/swig/tcl/CMakeLists.txt index bd280efa3..0b1abc604 100644 --- a/src/swig/tcl/CMakeLists.txt +++ b/src/swig/tcl/CMakeLists.txt @@ -1,6 +1,7 @@ set_source_files_properties(../mlt.i PROPERTIES USE_TARGET_INCLUDE_DIRECTORIES ON CPLUSPLUS ON) swig_add_library(mlttcl LANGUAGE tcl SOURCES ../mlt.i) -target_link_libraries(mlttcl mlt mlt++) +target_compile_options(mlttcl PRIVATE ${MLT_COMPILE_OPTIONS}) +target_link_libraries(mlttcl PRIVATE mlt mlt++) target_include_directories(mlttcl PRIVATE ${TCL_INCLUDE_PATH}) set_target_properties(mlttcl PROPERTIES OUTPUT_NAME "mlt") diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index d8fd9f330..26fec3566 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1,11 +1,13 @@ set(CMAKE_AUTOMOC ON) -foreach(QT_TEST_NAME animation audio events filter frame playlist properties repository service tractor) +foreach(QT_TEST_NAME animation audio events filter frame image playlist properties repository service tractor) add_executable(test_${QT_TEST_NAME} test_${QT_TEST_NAME}/test_${QT_TEST_NAME}.cpp) + target_compile_options(test_${QT_TEST_NAME} PRIVATE ${MLT_COMPILE_OPTIONS}) target_link_libraries(test_${QT_TEST_NAME} PRIVATE Qt5::Core Qt5::Test mlt++) add_test(NAME "QtTest:${QT_TEST_NAME}" COMMAND test_${QT_TEST_NAME}) - set_tests_properties("QtTest:${QT_TEST_NAME}" PROPERTIES - ENVIRONMENT "LANG=en_US;MLT_REPOSITORY=${CMAKE_BINARY_DIR}/src/modules;MLT_DATA=${CMAKE_SOURCE_DIR}/src/modules;MLT_PROFILES_PATH=${CMAKE_SOURCE_DIR}/profiles;MLT_PRESETS_PATH=${CMAKE_SOURCE_DIR}/presets") + if(NOT WIN32) + set_tests_properties("QtTest:${QT_TEST_NAME}" PROPERTIES ENVIRONMENT "LANG=en_US") + endif() endforeach() file(GLOB YML_FILES "${CMAKE_SOURCE_DIR}/src/modules/*/*.yml") diff --git a/src/tests/test_animation/test_animation.cpp b/src/tests/test_animation/test_animation.cpp index 101e55ac4..6d412fdd9 100644 --- a/src/tests/test_animation/test_animation.cpp +++ b/src/tests/test_animation/test_animation.cpp @@ -297,8 +297,8 @@ private Q_SLOTS: void SerializesInTimeFormat() { Profile profile; - Properties p; - p.set("_profile", profile.get_profile(), 0); + Properties p; + p.set("_profile", profile.get_profile(), 0); p.set("foo", "50=100; 60=60; 100=0"); // Cause the string to be interpreted as animated value. p.anim_get("foo", 0); @@ -311,8 +311,8 @@ private Q_SLOTS: void GetPropertyInTimeFormat() { Profile profile; - Properties p; - p.set("_profile", profile.get_profile(), 0); + Properties p; + p.set("_profile", profile.get_profile(), 0); p.set("foo", "50=100; 60=60; 100=0"); // Cause the string to be interpreted as animated value. p.anim_get_int("foo", 0); @@ -338,21 +338,51 @@ private Q_SLOTS: p.clear("foo"); QCOMPARE(p.get_animation("foo"), mlt_animation(0)); } - - void CanBeEscapedWithQuotes() - { - Properties p; - p.set("foo", "\"50=100; 60=60; 100=0\""); - // Quotes are retained when using the non-anim getter. - QCOMPARE(p.get("foo"), "\"50=100; 60=60; 100=0\""); - // Quotes are removed when using the anim getter. + + void CanBeEscapedWithQuotes() + { + Properties p; + p.set("foo", "\"50=100; 60=60; 100=0\""); + // Quotes are retained when using the non-anim getter. + QCOMPARE(p.get("foo"), "\"50=100; 60=60; 100=0\""); + // Quotes are removed when using the anim getter. QCOMPARE(p.anim_get("foo", 0), "50=100; 60=60; 100=0"); - // Anim strings may contain delimiters and equal signs if quoted. - p.set("foo", "50=100; 60=\"60; 100=0\";\"hello=world\""); - QCOMPARE(p.anim_get("foo", 0), "hello=world"); - QCOMPARE(p.anim_get("foo", 50), "100"); - QCOMPARE(p.anim_get("foo", 60), "60; 100=0"); - } + // Anim strings may contain delimiters and equal signs if quoted. + p.set("foo", "50=100; 60=\"60; 100=0\";\"hello=world\""); + QCOMPARE(p.anim_get("foo", 0), "hello=world"); + QCOMPARE(p.anim_get("foo", 50), "100"); + QCOMPARE(p.anim_get("foo", 60), "60; 100=0"); + } + + void ShiftFramesPositive() + { + 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()); + a.shift_frames( 60 ); + QCOMPARE(a.key_get_frame(0), 110); + QCOMPARE(a.key_get_frame(1), 120); + QCOMPARE(a.key_get_frame(2), 160); + QCOMPARE(a.key_get_frame(3), -1); + } + + void ShiftFramesNegative() + { + 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()); + a.shift_frames( -60 ); + QCOMPARE(a.key_get_frame(0), -10); + QCOMPARE(a.key_get_frame(1), 0); + QCOMPARE(a.key_get_frame(2), 40); + QCOMPARE(a.key_get_frame(3), -1); + } }; QTEST_APPLESS_MAIN(TestAnimation) diff --git a/src/tests/test_events/test_events.cpp b/src/tests/test_events/test_events.cpp index b4625d495..134223242 100644 --- a/src/tests/test_events/test_events.cpp +++ b/src/tests/test_events/test_events.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Meltytech, LLC + * Copyright (C) 2019-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 @@ -44,10 +44,10 @@ class TestEvents : public QObject QVERIFY(owner == m_properties); } - static void onPropertyChanged(mlt_properties owner, TestEvents* self, char* name) + static void onPropertyChanged(mlt_properties owner, TestEvents* self, mlt_event_data data) { QVERIFY(self != nullptr); - QCOMPARE(name, "foo"); + QCOMPARE(Mlt::EventData(data).to_string(), "foo"); self->checkOwner(owner); } @@ -58,7 +58,7 @@ private Q_SLOTS: Profile profile; Producer producer(profile, "noise"); QVERIFY(producer.is_valid()); - Event* event = producer.listen("property-changed", this, (mlt_transmitter) onPropertyChanged); + Event* event = producer.listen("property-changed", this, (mlt_listener) onPropertyChanged); QVERIFY(event != nullptr); QVERIFY(event->is_valid()); m_properties = producer.get_properties(); @@ -71,7 +71,7 @@ private Q_SLOTS: Profile profile; Producer producer(profile, "noise"); m_properties = nullptr; - Event* event = producer.listen("property-changed", nullptr, (mlt_transmitter) onPropertyChanged); + Event* event = producer.listen("property-changed", nullptr, (mlt_listener) onPropertyChanged); QVERIFY(event != nullptr); QVERIFY(event->is_valid()); event->block(); @@ -84,7 +84,7 @@ private Q_SLOTS: Profile profile; Producer producer(profile, "noise"); m_properties = producer.get_properties(); - Event* event = producer.listen("property-changed", this, (mlt_transmitter) onPropertyChanged); + Event* event = producer.listen("property-changed", this, (mlt_listener) onPropertyChanged); QVERIFY(event != nullptr); QVERIFY(event->is_valid()); event->block(); diff --git a/src/tests/test_filter/test_filter.cpp b/src/tests/test_filter/test_filter.cpp index 68f9112be..58347ed26 100644 --- a/src/tests/test_filter/test_filter.cpp +++ b/src/tests/test_filter/test_filter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Brian Matherly + * Copyright (C) 2015 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,7 +47,7 @@ private Q_SLOTS: Filter filter(profile, "resize"); int width = 0; int height = 0; - mlt_image_format format = mlt_image_rgb24; + mlt_image_format format = mlt_image_rgb; // Get a frame from the producer Frame* frame = producer.get_frame(); diff --git a/src/tests/test_frame/test_frame.cpp b/src/tests/test_frame/test_frame.cpp index df6869b57..3507e498e 100644 --- a/src/tests/test_frame/test_frame.cpp +++ b/src/tests/test_frame/test_frame.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Brian Matherly + * Copyright (C) 2015 Meltytech, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/tests/test_image/test_image.cpp b/src/tests/test_image/test_image.cpp new file mode 100644 index 000000000..c2d74c4d6 --- /dev/null +++ b/src/tests/test_image/test_image.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 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 consumer library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include +using namespace Mlt; + +class TestImage : public QObject +{ + Q_OBJECT + +public: + TestImage() + { + Factory::init(); + } + +private Q_SLOTS: + + void DefaultConstructor() + { + Image i; + QVERIFY(i.width() == 0); + } + + void ConstructFromImage() + { + mlt_image image = mlt_image_new(); + image->width = 500; + Image i(image); + QCOMPARE(i.width(), 500); + } + + void ConstructAndAlloc() + { + Image i(1920, 1080, mlt_image_rgb ); + QVERIFY(i.plane(0) != nullptr); + } + + void PlaneAndStrideRgb24() + { + Image i(1920, 1080, mlt_image_rgb ); + QVERIFY(i.plane(0) != nullptr); + QCOMPARE(i.stride(0), 1920 * 3); + QVERIFY(i.plane(1) == nullptr); + QCOMPARE(i.stride(1), 0); + QVERIFY(i.plane(2) == nullptr); + QCOMPARE(i.stride(2), 0); + QVERIFY(i.plane(3) == nullptr); + QCOMPARE(i.stride(3), 0); + } + + void PlaneAndStrideRgb24a() + { + Image i(1920, 1080, mlt_image_rgba ); + QVERIFY(i.plane(0) != nullptr); + QCOMPARE(i.stride(0), 1920 * 4); + QVERIFY(i.plane(1) == nullptr); + QCOMPARE(i.stride(1), 0); + QVERIFY(i.plane(2) == nullptr); + QCOMPARE(i.stride(2), 0); + QVERIFY(i.plane(3) == nullptr); + QCOMPARE(i.stride(3), 0); + } + + void PlaneAndStrideYuv422() + { + Image i(1920, 1080, mlt_image_yuv422 ); + QVERIFY(i.plane(0) != nullptr); + QCOMPARE(i.stride(0), 1920 * 2); + QVERIFY(i.plane(1) == nullptr); + QCOMPARE(i.stride(1), 0); + QVERIFY(i.plane(2) == nullptr); + QCOMPARE(i.stride(2), 0); + QVERIFY(i.plane(3) == nullptr); + QCOMPARE(i.stride(3), 0); + } + + void PlaneAndStrideYuv420p() + { + Image i(1920, 1080, mlt_image_yuv420p ); + QVERIFY(i.plane(0) != nullptr); + QCOMPARE(i.stride(0), 1920); + QVERIFY(i.plane(1) != nullptr); + QCOMPARE(i.stride(1), 1920 / 2); + QVERIFY(i.plane(2) != nullptr); + QCOMPARE(i.stride(2), 1920 / 2); + QVERIFY(i.plane(3) == nullptr); + QCOMPARE(i.stride(3), 0); + } + + void PlaneAndStrideYuv422p16() + { + Image i(1920, 1080, mlt_image_yuv420p ); + QVERIFY(i.plane(0) != nullptr); + QCOMPARE(i.stride(0), 1920); + QVERIFY(i.plane(1) != nullptr); + QCOMPARE(i.stride(1), 1920 / 2); + QVERIFY(i.plane(2) != nullptr); + QCOMPARE(i.stride(2), 1920 / 2); + QVERIFY(i.plane(3) == nullptr); + QCOMPARE(i.stride(3), 0); + } + + void GetSetColorspace() + { + Image i(1920, 1080, mlt_image_rgb ); + i.set_colorspace(mlt_colorspace_bt709); + QCOMPARE(i.colorspace(), mlt_colorspace_bt709); + } + + void InitAlpha() + { + Image i(1920, 1080, mlt_image_rgb ); + i.init_alpha(); + QVERIFY(i.plane(3) != nullptr); + } +}; + +QTEST_APPLESS_MAIN(TestImage) + +#include "test_image.moc" diff --git a/src/tests/test_image/test_image.pro b/src/tests/test_image/test_image.pro new file mode 100644 index 000000000..b9a59d7cc --- /dev/null +++ b/src/tests/test_image/test_image.pro @@ -0,0 +1,3 @@ +include(../common.pri) +TARGET = test_image +SOURCES += test_image.cpp diff --git a/src/tests/test_properties/test_properties.cpp b/src/tests/test_properties/test_properties.cpp index f13c347b9..ed7b1e9ca 100644 --- a/src/tests/test_properties/test_properties.cpp +++ b/src/tests/test_properties/test_properties.cpp @@ -919,6 +919,65 @@ private Q_SLOTS: QCOMPARE(p.anim_get("key", 45), "hello world"); } + + void PropertyRefreshOnAnimationChange() + { + // Create an animation property from string and see that it works. + // Get the animation and modify the first position. + // Ensure that change affects other get() functions + + { + Properties p; + p.set("foo", "10=100; 20=200"); + QCOMPARE(p.get_double("foo"), 10.0); + // Call anim_get_double() to create the animation + QCOMPARE(p.anim_get_double("foo", 15, 20 ), 150.0); + Mlt::Animation animation = p.get_animation("foo"); + animation.key_set_frame(0, 15); + QCOMPARE(p.get_double("foo"), 15.0); + } + + { + Properties p; + p.set("foo", "10=100;20=200"); + QCOMPARE(p.anim_get_double("foo", 15, 20 ), 150.0); + Mlt::Animation animation = p.get_animation("foo"); + animation.key_set_frame(0, 15); + QCOMPARE(p.anim_get_double("foo", 15, 0 ), 100.0); + } + + { + Properties p; + p.set("foo", "10=100; 20=200"); + QCOMPARE(p.get_int("foo"), 10); + // Call anim_get_int() to create the animation + QCOMPARE(p.anim_get_int("foo", 15, 20 ), 150); + Mlt::Animation animation = p.get_animation("foo"); + animation.key_set_frame(0, 15); + QCOMPARE(p.get_int("foo"), 15); + } + + { + Properties p; + p.set("foo", "10=100; 20=200"); + QCOMPARE(p.anim_get_int("foo", 15, 20 ), 150); + Mlt::Animation animation = p.get_animation("foo"); + animation.key_set_frame(0, 15); + QCOMPARE(p.anim_get_int("foo", 15, 0 ), 100); + } + + { + Properties p; + p.set("foo", "10=100;20=200"); + // Call anim_get_int() to create the animation + QCOMPARE(p.anim_get_int("foo", 15, 20 ), 150); + Mlt::Animation animation = p.get_animation("foo"); + QCOMPARE(p.get("foo"), "10=100;20=200"); + animation.key_set_frame(0, 15); + QCOMPARE(p.get("foo"), "15=100;20=200"); + } + } + void test_mlt_rect() { mlt_property p = mlt_property_init(); diff --git a/src/tests/test_service/test_service.cpp b/src/tests/test_service/test_service.cpp index 38cc9e0cc..969b000be 100644 --- a/src/tests/test_service/test_service.cpp +++ b/src/tests/test_service/test_service.cpp @@ -40,13 +40,13 @@ private Q_SLOTS: { Profile profile; Producer producer(profile, "color"); - QCOMPARE(mlt_service_identify(producer.get_service()), producer_type); + QCOMPARE(mlt_service_identify(producer.get_service()), mlt_service_producer_type); Filter filter(profile, "resize"); - QCOMPARE(mlt_service_identify(filter.get_service()), filter_type); + QCOMPARE(mlt_service_identify(filter.get_service()), mlt_service_filter_type); Transition transition(profile, "mix"); - QCOMPARE(mlt_service_identify(transition.get_service()), transition_type); + QCOMPARE(mlt_service_identify(transition.get_service()), mlt_service_transition_type); Consumer consumer(profile, "null"); - QCOMPARE(mlt_service_identify(consumer.get_service()), consumer_type); + QCOMPARE(mlt_service_identify(consumer.get_service()), mlt_service_consumer_type); } void CanIdentifyServicesFromAPI() @@ -54,19 +54,19 @@ private Q_SLOTS: mlt_profile profile = mlt_profile_init(NULL); mlt_playlist playlist = mlt_playlist_new(profile); - QCOMPARE(mlt_service_identify(MLT_PLAYLIST_SERVICE(playlist)), playlist_type); + QCOMPARE(mlt_service_identify(MLT_PLAYLIST_SERVICE(playlist)), mlt_service_playlist_type); mlt_tractor tractor = mlt_tractor_new(); - QCOMPARE(mlt_service_identify(MLT_TRACTOR_SERVICE(tractor)), tractor_type); - QCOMPARE(mlt_service_identify(MLT_MULTITRACK_SERVICE(mlt_tractor_multitrack(tractor))), multitrack_type); + QCOMPARE(mlt_service_identify(MLT_TRACTOR_SERVICE(tractor)), mlt_service_tractor_type); + QCOMPARE(mlt_service_identify(MLT_MULTITRACK_SERVICE(mlt_tractor_multitrack(tractor))), mlt_service_multitrack_type); mlt_producer producer = mlt_producer_new(profile); - QCOMPARE(mlt_service_identify(MLT_PRODUCER_SERVICE(producer)), producer_type); + QCOMPARE(mlt_service_identify(MLT_PRODUCER_SERVICE(producer)), mlt_service_producer_type); mlt_filter filter = mlt_filter_new(); - QCOMPARE(mlt_service_identify(MLT_FILTER_SERVICE(filter)), filter_type); + QCOMPARE(mlt_service_identify(MLT_FILTER_SERVICE(filter)), mlt_service_filter_type); mlt_transition transition = mlt_transition_new(); - QCOMPARE(mlt_service_identify(MLT_TRANSITION_SERVICE(transition)), transition_type); + QCOMPARE(mlt_service_identify(MLT_TRANSITION_SERVICE(transition)), mlt_service_transition_type); mlt_consumer consumer = mlt_consumer_new(profile); - QCOMPARE(mlt_service_identify(MLT_CONSUMER_SERVICE(consumer)), consumer_type); + QCOMPARE(mlt_service_identify(MLT_CONSUMER_SERVICE(consumer)), mlt_service_consumer_type); } private: diff --git a/src/tests/tests.pro b/src/tests/tests.pro index 593d5b030..f7d9d324e 100644 --- a/src/tests/tests.pro +++ b/src/tests/tests.pro @@ -3,6 +3,7 @@ SUBDIRS = test_audio \ test_filter \ test_events \ test_frame \ + test_image \ test_playlist \ test_properties \ test_repository \