diff --git a/.gitignore b/.gitignore index c56db7b..fc9df44 100644 --- a/.gitignore +++ b/.gitignore @@ -3,9 +3,9 @@ counter.sh ardour/ ardour_old/ old/ -test/private_aaf include/libaaf/version.h AAF Structure.md clang-format-sample-file.c .clang-format -test/private/* +test/private +test/private_aaf diff --git a/CMakeLists.txt b/CMakeLists.txt index cb6e6b4..828ca84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,17 +7,20 @@ project( "libaaf" HOMEPAGE_URL "https://github.com/agfline/LibAAF" ) option( BUILD_STATIC_LIB "Build the static library" OFF ) -option( BUILD_SHARED_LIB "Build the shared library" ON ) -option( BUILD_TOOLS "Build AAFInfo and AAFExtract programs" ON ) +option( BUILD_SHARED_LIB "Build the shared library" ON ) +option( BUILD_TOOLS "Build aaftool" ON ) option( XBUILD_WIN "Cross compile libaaf on Linux for Windows" OFF ) +option( BUILD_DOC "Build documentation" ON ) +option( BUILD_UNIT_TEST "Build unit test programs" ON ) set( LIBAAF_VERSION "GIT" CACHE STRING "Set version manualy, git version used otherwise" ) set( LIBAAF_LIB_OUTPUT_NAME "aaf" ) -set( LIBAAF_LIB_SRC_PATH ${PROJECT_SOURCE_DIR}/src ) -set( LIBAAF_TOOLS_SRC_PATH ${PROJECT_SOURCE_DIR}/tools ) -set( LIBAAF_EXAMPLES_SRC_PATH ${PROJECT_SOURCE_DIR}/examples ) -set( LIBAAF_TEST_PATH ${PROJECT_SOURCE_DIR}/test ) +set( LIBAAF_LIB_SRC_PATH ${PROJECT_SOURCE_DIR}/src ) +set( LIBAAF_TOOLS_SRC_PATH ${PROJECT_SOURCE_DIR}/tools ) +set( LIBAAF_DOC_INPUT_PATH ${PROJECT_SOURCE_DIR}/doc ) +set( LIBAAF_DOC_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/build/doc ) +set( LIBAAF_TEST_PATH ${PROJECT_SOURCE_DIR}/test ) set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) @@ -29,7 +32,6 @@ endif() - function( laaf_set_version ) find_package( Git ) @@ -70,6 +72,36 @@ endif() message( "libaaf version: ${LIBAAF_VERSION}" ) + +if ( BUILD_DOC ) + find_package(Doxygen) + if ( DOXYGEN_FOUND ) + + set( DOXYGEN_PROJECT_NAME ${PROJECT_NAME} ) + set( DOXYGEN_PROJECT_NUMBER ${LIBAAF_VERSION} ) + set( DOXYGEN_PROJECT_BRIEF ${PROJECT_BRIEF} ) + + set( DOXYGEN_USE_MDFILE_AS_MAINPAGE ${PROJECT_SOURCE_DIR}/README.md ) + set( DOXYGEN_INPUT_DIR "${PROJECT_SOURCE_DIR}/include/ ${PROJECT_SOURCE_DIR}/src/ ${PROJECT_SOURCE_DIR}/README.md" ) + set( DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/doxygen ) + + configure_file( ${LIBAAF_DOC_INPUT_PATH}/doxygen.in ${PROJECT_SOURCE_DIR}/build/doxygen.conf @ONLY ) + + FILE( MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR} ) + + # note the option ALL which allows to build the docs together with the application + add_custom_target( doc + COMMAND ${DOXYGEN_EXECUTABLE} ${PROJECT_SOURCE_DIR}/build/doxygen.conf + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen" + VERBATIM ) + + else (DOXYGEN_FOUND) + message( "Doxygen need to be installed to generate the documentation" ) + endif (DOXYGEN_FOUND) +endif (BUILD_DOC) + + configure_file( ${PROJECT_SOURCE_DIR}/libaaf.pc.in ${CMAKE_BINARY_DIR}/libaaf.pc @ONLY ) @@ -78,12 +110,16 @@ if ( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" ) set( LIBAAF_COMPILE_OPTIONS -W -Wstrict-prototypes -Wmissing-prototypes -Wall -Wcast-qual -Wcast-align -Wextra -Wwrite-strings -Wunsafe-loop-optimizations -Wlogical-op -std=c99 -pedantic -Wshadow # = Ardour's Waf --strict --c-strict - # -Wconversion + -Wsign-conversion + -Wconversion -Wcast-align=strict -O3 -g + -D_XOPEN_SOURCE=500 + # -pg -fdebug-prefix-map=${SRC_PATH}=. ) + # set( LIBAAF_LINK_OPTIONS -pg ) if ( XBUILD_WIN ) message( "┌─────────────────────────────┐" ) message( "│ Cross compiling for Windows │" ) @@ -113,7 +149,7 @@ elseif ( ${CMAKE_SYSTEM_NAME} MATCHES "Windows" ) set( PROG_SUFFIX ".exe" ) endif() -# TODO: not required when compiling on linux but "missing header" when x-compiling +# TODO: not required with gcc but "missing header" whith mingw-w64 include_directories( ${PROJECT_SOURCE_DIR}/include ) @@ -133,20 +169,23 @@ set( LIBAAF_LIB_SOURCES ${LIBAAF_LIB_SRC_PATH}/AAFIface/AAFIface.c ${LIBAAF_LIB_SRC_PATH}/AAFIface/AAFIParser.c - ${LIBAAF_LIB_SRC_PATH}/AAFIface/AAFIAudioFiles.c + ${LIBAAF_LIB_SRC_PATH}/AAFIface/AAFIEssenceFile.c ${LIBAAF_LIB_SRC_PATH}/AAFIface/RIFFParser.c ${LIBAAF_LIB_SRC_PATH}/AAFIface/URIParser.c ${LIBAAF_LIB_SRC_PATH}/AAFIface/ProTools.c ${LIBAAF_LIB_SRC_PATH}/AAFIface/Resolve.c + ${LIBAAF_LIB_SRC_PATH}/AAFIface/MediaComposer.c ${LIBAAF_LIB_SRC_PATH}/common/utils.c - ${LIBAAF_LIB_SRC_PATH}/debug.c + # ${LIBAAF_LIB_SRC_PATH}/common/ConvertUTF.c + ${LIBAAF_LIB_SRC_PATH}/common/log.c ) if ( BUILD_SHARED_LIB ) add_library( aaf-shared SHARED ${LIBAAF_LIB_SOURCES} ) target_compile_options( aaf-shared PUBLIC ${LIBAAF_COMPILE_OPTIONS} ) + target_link_options( aaf-shared PUBLIC ${LIBAAF_LINK_OPTIONS} ) target_include_directories( aaf-shared PUBLIC "${CMAKE_BINARY_DIR}/include/" ) set_target_properties( aaf-shared PROPERTIES OUTPUT_NAME ${LIBAAF_LIB_OUTPUT_NAME} @@ -160,6 +199,7 @@ endif( BUILD_SHARED_LIB ) if ( BUILD_STATIC_LIB ) add_library( aaf-static STATIC ${LIBAAF_LIB_SOURCES} ) target_compile_options( aaf-static PUBLIC ${LIBAAF_COMPILE_OPTIONS} ) + target_link_options( aaf-static PUBLIC ${LIBAAF_LINK_OPTIONS} ) target_include_directories( aaf-static PUBLIC "${CMAKE_BINARY_DIR}/include/" ) set_target_properties( aaf-static PROPERTIES OUTPUT_NAME ${LIBAAF_LIB_OUTPUT_NAME} @@ -179,9 +219,9 @@ endif( BUILD_STATIC_LIB ) if ( BUILD_TOOLS ) if ( ${LINK_LIB} MATCHES "aaf-static" ) - message( "Building AAFIface and AAFExtract upon static library" ) + message( "Building aaftool upon static library" ) elseif( ${LINK_LIB} MATCHES "aaf-shared" ) - message( "Building AAFIface and AAFExtract upon shared library" ) + message( "Building aaftool upon shared library" ) endif() if ( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" ) @@ -190,29 +230,45 @@ if ( BUILD_TOOLS ) link_libraries( ${LINK_LIB} ) endif() - add_executable( AAFInfo - ${LIBAAF_TOOLS_SRC_PATH}/AAFInfo.c - ${LIBAAF_TOOLS_SRC_PATH}/common.c + add_executable( aaftool + ${LIBAAF_TOOLS_SRC_PATH}/AAFTool.c ${LIBAAF_TOOLS_SRC_PATH}/thirdparty/libTC.c ) - add_executable( AAFExtract - ${LIBAAF_TOOLS_SRC_PATH}/AAFExtract.c - ${LIBAAF_TOOLS_SRC_PATH}/common.c - ) - target_include_directories( AAFInfo PRIVATE "${CMAKE_BINARY_DIR}/include/" ) - target_include_directories( AAFExtract PRIVATE "${CMAKE_BINARY_DIR}/include/" ) + set_target_properties( aaftool PROPERTIES SUFFIX "${PROG_SUFFIX}" ) - set_target_properties( AAFInfo PROPERTIES SUFFIX "${PROG_SUFFIX}" ) - set_target_properties( AAFExtract PROPERTIES SUFFIX "${PROG_SUFFIX}" ) - - target_compile_options( AAFInfo PUBLIC ${LIBAAF_COMPILE_OPTIONS} ) - target_compile_options( AAFExtract PUBLIC ${LIBAAF_COMPILE_OPTIONS} ) + target_include_directories( aaftool PRIVATE "${CMAKE_BINARY_DIR}/include/" ) + target_compile_options( aaftool PUBLIC ${LIBAAF_COMPILE_OPTIONS} ) + target_link_options( aaftool PUBLIC ${LIBAAF_LINK_OPTIONS} ) endif( BUILD_TOOLS ) +if ( BUILD_UNIT_TEST ) + + if ( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" ) + link_libraries( ${LINK_LIB} "-lm" ) + else() + link_libraries( ${LINK_LIB} ) + endif() + + add_executable( test_utils + ${LIBAAF_TEST_PATH}/units/test_utils.c ) + + add_executable( test_libtc + ${LIBAAF_TEST_PATH}/units/test_libtc.c + ${LIBAAF_TOOLS_SRC_PATH}/thirdparty/libTC.c ) + + add_executable( test_uri + ${LIBAAF_TEST_PATH}/units/test_uri.c ) + + set_target_properties( test_utils PROPERTIES SUFFIX "${PROG_SUFFIX}" ) + set_target_properties( test_libtc PROPERTIES SUFFIX "${PROG_SUFFIX}" ) + set_target_properties( test_uri PROPERTIES SUFFIX "${PROG_SUFFIX}" ) + +endif( BUILD_UNIT_TEST ) + if ( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" ) @@ -226,8 +282,7 @@ if ( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" ) endif() if ( BUILD_TOOLS ) - install( TARGETS AAFInfo DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} ) - install( TARGETS AAFExtract DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} ) + install( TARGETS aaftool DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} ) endif() install( DIRECTORY ${PROJECT_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h*" ) @@ -249,7 +304,6 @@ add_custom_target( ./src ./include ./tools - # ./examples # ./test COMMAND cd "${CMAKE_BINARY_DIR}" && @@ -264,5 +318,22 @@ add_custom_target( clean-cmake-files COMMAND rm -rf "${CMAKE_BINARY_DIR}/*.cmake" ) -add_custom_target( test - COMMAND ${LIBAAF_TEST_PATH}/test.sh --run-from-cmake ) +if ( XBUILD_WIN ) + add_custom_target( test + COMMAND wine ${CMAKE_BINARY_DIR}/bin/test_libtc${PROG_SUFFIX} + COMMAND wine ${CMAKE_BINARY_DIR}/bin/test_uri${PROG_SUFFIX} + COMMAND wine ${CMAKE_BINARY_DIR}/bin/test_utils${PROG_SUFFIX} + COMMAND ${LIBAAF_TEST_PATH}/test.py --wine ) +elseif ( ${CMAKE_SYSTEM_NAME} MATCHES "Windows" ) + add_custom_target( test + COMMAND ${CMAKE_BINARY_DIR}/bin/test_libtc${PROG_SUFFIX} + COMMAND ${CMAKE_BINARY_DIR}/bin/test_uri${PROG_SUFFIX} + COMMAND ${CMAKE_BINARY_DIR}/bin/test_utils${PROG_SUFFIX} + COMMAND ${LIBAAF_TEST_PATH}/test.py --run-from-cmake ) +else() + add_custom_target( test + COMMAND ${CMAKE_BINARY_DIR}/bin/test_libtc + COMMAND ${CMAKE_BINARY_DIR}/bin/test_uri + COMMAND ${CMAKE_BINARY_DIR}/bin/test_utils + COMMAND ${LIBAAF_TEST_PATH}/test.py --run-from-cmake ) +endif() diff --git a/README.md b/README.md index dde90e8..c676f7c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# LibAAF +# libaaf > [!WARNING] > > While major version number remains 0, API MUST NOT be considered stable. @@ -6,62 +6,210 @@ > Releases are made everytime libaaf code is updated into Ardour source tree. -LibAAF is a C coded library for AAF file handling. The AAF beeing a quite complex file format, the main goal here is to get an easy-to-implement, audio oriented, FOSS solution. +libaaf is a C coded library for **AAF file reading**. The AAF beeing a quite complex file format, libaaf provides an easy-to-implement, audio-oriented, FLOSS solution. +libaaf runs under Linux, Windows and OSX. -The library is composed of three parts : +## aaftool -* **LibCFB** : Low-level AAF's *Compound File Binary* handling -* **AAFCore** : AAF Class/Object manipulations -* **AAFIface** : Abstraction layer for easy data access. +**aaftool** is a command line tool to inspect AAF structure, essences, tracks and clips, extract embedded media files, etc. -One should only use the **AAFIface** interface to manipulate files and retrieve data. +``` +aaftool Copyright (c) 2017-2024 Adrien Gesta-Fline +libaaf v0.6-45-g9171e40-dirty + +usage: aaftool [analysis|extraction] [options] [AAFFILE] + + CFB Analysis: + + --cfb-header Display CFB Header. + --cfb-fat Display CFB FAT. + --cfb-minifat Display CFB MiniFAT. + --cfb-difat Display CFB DiFAT. + --cfb-nodes Display CFB node list. + + --cfb-node Display node located at the given . + + + AAF Analysis: + + --aaf-summary Display informations from both header and identification objects. + --aaf-essences Display retrieved AAF audio and video essences. + --aaf-clips Display retrieved AAF audio and video clips. + --aaf-classes Display classes contained in AAF file. + --aaf-meta Display classes and properties from the MetaDictionary. + --aaf-properties Display properties of all objects in file. + + --trace Display AAF class/object structure while parsing. + --dump-meta Display MetaProperties details for each parsed class containing meta properties. + --dump_tagged_value Display standard TaggedValue properties of Mobs and Components objects. + --dump-class Display aaf properties of a specific AAFClass when it is parsed. + --dump-class-raw Display raw properties of a specific AAFClass when it is parsed. + + + Embedded Media Extraction: + + --extract-essences Extract all embedded audio essences as they are stored (wav or aiff), + unless --extract-format is set. Raw PCM is extracted as wav file. + --extract-clips Extract all embedded audio clips (trimed essences) as wav files. + --extract-path Location where embedded files are extracted. + --extract-format Force extract format to wav or broadcast wav. + --extract-mobid Name extracted files with their MobID. This also prevents any non-latin + character in filename. + + + Software Specific Options: -## Support + --pt-true-fades Replace rendered ProTools fade clips with real fades when possible, + when surrounding clips has enough handle size. + --pt-remove-sae Remove all ProTools "sample accurate edit" small clips. -LibAAF only supports the reading of AAF files, it cannot write ones. -LibAAF was widely tested with : + Options: -* Avid Media Composer 8.4.5 - 8.8.3 - 18.12.5 -* Adobe Premiere Pro (CC 2018) 12.0 - 12.1.1 + --media-location Location of external audio and video essence files. + + --samplerate Sample rate used for converting displayed position + and duration values. If not set, AAF dominant sample + rate is used. + --pos-format Position and duration display format. + --show-automation Show track and clip automation values when --aaf-clips is set. + --show-metadata Show source and clip metadata when --aaf-essences or --aaf-clips is set. + + --hide-path Don't print full path to located essences when --aaf-essences is set. + + --no-color Disable colored output. + --log-file Save output to file instead of stdout. + + --verb 0=quiet 1=error 2=warning 3=debug. +``` + +## libaaf Features + +* Supports embedded raw PCM/WAV/AIFF essences and provides function for file extraction. +* Supports external essence files, with auto-location function (relative to AAF file location). +* Supports multi-channel clip out of a single multi-channel essence file. +* Supports multi-channel clip out of multiple single-channel essence files. +* Supports multi-channel tracks. +* Supports fade in/out and x-fades. +* Supports clip-based and track-based fixed and varying gain. +* Supports track-based fixed/varying pan. +* Supports timecode +* Supports composition metadata (comments, tapeid, etc.) +* libaaf being audio-oriented right now, it only supports a single video clip. Better video support could be implemented later. + +AAF is known for its poor interoperability, each software having its own way to describe things, some adding non-standard features. libaaf implements all of those *proprietary features* that have been observed so far in dozens of files coming from the following software : + +* Avid Media Composer 8.4.5 - 8.8.3 - 18.12.5 - 23.12 +* Adobe Premiere Pro 12.0 - 23.5.0 * ProTools 10.3.10 - 2023.12 -* Logic Pro 9.1.7 - 10.7.4 * Davinci Resolve 17.4.6 - 18.5 +* Logic Pro 9.1.7 - 10.7.4 * Fairlight Evo/Dream 2.5.1 - 4.1.75 +### Avid Media Composer + +* Supports *SubClip* CompositionMobs. +* Supports *AdjustedClip* CompositionMobs. +* Supports proprietary *Audio Warp* OperationGroup (leading to a wrong clip source offset when importing in most commercial implementations). +* Supports proprietary markers: position, length, name, description, color. +* Supports proprietary track solo / mute. +* Supports proprietary fade curve types. +* Supports proprietary source metadata. +* Supports proprietary *SubClip* metadata. + +### ProTools + +* Supports recovering of real fades, out of rendered fade clips. +* Supports removing of *sample accurate edit* clips, recovering length of useful clips. -| | | | -|------------------------------------------------|:-:|----------------------------------------| -| Composition Name | x | *Full support* | -| Track Names | x | *Full support* | -| Clip Names | x | *built upon source file names* | -| Original essence file names | x | *Full support* | -| Embedded PCM Essences | x | *Full support* | -| Embedded WAV Essences | x | *Full support* | -| Embedded AIFF Essences | x | *Full support* | -| Embedded AES3 Essences | - | *Missing from the specs / Not encountered yet* | -| External WAV Essences | x | *Full support* | -| External AIFF Essences | x | *Full support* | -| External MXF Essences | x | *Full support* | -| External Non-PCM Essences (MP3, AAC, etc.) | x | *Full support* | -| Multi-channel clip out of a multi-channel file | x | *Full support* | -| Multi-channel clip out of multiple mono files | x | *Full support* | -| Fades in/out - XFades | x | *Full support* | -| Legacy Fades in/out - XFades | - | *useless ? obsolete since at least AAFv1.1 - 2005* | -| Clip based Gain (fixed/varying) | x | *Full support* | -| Track based Gain (fixed/varying) | x | *Full support* | -| Track based PAN (fixed/varying) | x | *Full support* | +### Davinci Resolve +* Supports proprietary markers. + + +## Library usage + +```C +#include + +/* allocate a new AAF_Iface object */ +AAF_Iface *aafi = aafi_alloc( NULL ); + +if ( !aafi ) { + return -1; /* error */ +} + +/* set verbosity level, optional file pointer or callback function */ +aafi_set_debug( aafi, VERB_DEBUG, 1, stdout, NULL, NULL ); + +/* set libaaf options */ +aafi_set_option_int( aafi, "trace", 1 ); +aafi_set_option_int( aafi, "dump_meta", 1 ); +aafi_set_option_int( aafi, "dump_tagged_value", 1 ); +aafi_set_option_int( aafi, "protools", (AAFI_PROTOOLS_OPT_REPLACE_CLIP_FADES | AAFI_PROTOOLS_OPT_REMOVE_SAMPLE_ACCURATE_EDIT) ); +aafi_set_option_str( aafi, "media_location", "./media/" ); +aafi_set_option_str( aafi, "dump_class_aaf_properties", "AAFClassID_TimelineMobSlot" ); + +/* load AAF file */ +if ( aafi_load_file( aafi, "./file.aaf" ) ) { + return -1; /* error */ +} +``` + +### Retrieve Media Essences + +```C +aafiAudioEssenceFile *audioEssenceFile = NULL; + +AAFI_foreachAudioEssenceFile( aafi, audioEssenceFile ) { + /* process audio essence */ +} +``` + +### Retrieve Tracks and Clips + +```C +aafiAudioTrack *audioTrack = NULL; +aafiTimelineItem *audioItem = NULL; + +AAFI_foreachAudioTrack( aafi, audioTrack ) { + + /* process track */ + + AAFI_foreachTrackItem( audioTrack, audioItem ) { + + aafiAudioClip *audioClip = aafi_timelineItemToAudioClip( audioItem ); + aafiTransition *crossFade = aafi_timelineItemToCrossFade( audioItem ); + + if ( audioClip ) { + + /* process clip */ + + aafiTransition *fadein = aafi_getFadeIn( audioClip ); + aafiTransition *fadeout = aafi_getFadeOut( audioClip ); + + if ( fadein ) { + /* process fade in */ + } + + if ( fadeout ) { + /* process fade out */ + } + } + else if ( crossFade ) { + /* process cross fade */ + } + } +} +``` ## Build +libaaf doesn't rely on any specific dependency. + ``` cd build cmake .. make ``` - -## Ardour Support - -LibAAF was added to Ardour version 8.2 diff --git a/doc/.gitignore b/doc/.gitignore deleted file mode 100644 index 391f751..0000000 --- a/doc/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -* - -!style.css -!Makefile -!Doxygen.conf - -!.gitignore diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 30d5e26..0000000 --- a/doc/Makefile +++ /dev/null @@ -1,10 +0,0 @@ - - -all: doc - -doc: - @echo - @echo "++++++++++++++++++++++++++++++" - @echo "+++ Building Documentation +++" - @echo "++++++++++++++++++++++++++++++" - doxygen Doxygen.conf diff --git a/doc/Doxygen.conf b/doc/doxygen.in similarity index 78% rename from doc/Doxygen.conf rename to doc/doxygen.in index c052b85..b7861c6 100644 --- a/doc/Doxygen.conf +++ b/doc/doxygen.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.13 +# Doxyfile 1.9.4 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,16 +12,25 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 @@ -32,44 +41,56 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = LibAAF +PROJECT_NAME = @DOXYGEN_PROJECT_NAME@ # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = @DOXYGEN_PROJECT_NUMBER@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = +PROJECT_BRIEF = @DOXYGEN_PROJECT_BRIEF@ # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = +PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = +OUTPUT_DIRECTORY = @DOXYGEN_OUTPUT_DIR@ -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# numer of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode @@ -81,14 +102,14 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English @@ -162,7 +183,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -171,7 +192,7 @@ STRIP_FROM_PATH = # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -189,6 +210,16 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus @@ -209,6 +240,14 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. @@ -232,20 +271,18 @@ TAB_SIZE = 4 # the documentation. An alias has the form: # name=value # For example adding -# "sideeffect=@par Side Effects:\n" +# "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. - -ALIASES = "TODO=@todo" \ - "FIXME=@todo" - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) -TCL_SUBST = +ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For @@ -253,7 +290,7 @@ TCL_SUBST = # members will be omitted, etc. # The default value is: NO. -OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored @@ -275,28 +312,40 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: -# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: -# Fortran. In the later case the parser tries to guess whether the code is fixed -# or free formatted code, this is the default for Fortran type files), VHDL. For -# instance to make doxygen treat .inc files as Fortran files (default is PHP), -# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. -EXTENSION_MAPPING = +EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. +# documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. @@ -308,10 +357,10 @@ MARKDOWN_SUPPORT = YES # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 0. +# Minimum value: 0, maximum value: 99, default value: 5. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. -TOC_INCLUDE_HEADINGS = 0 +TOC_INCLUDE_HEADINGS = 5 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can @@ -338,7 +387,7 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. @@ -409,7 +458,7 @@ INLINE_SIMPLE_STRUCTS = NO # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. -TYPEDEF_HIDES_STRUCT = YES +TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be @@ -424,6 +473,19 @@ TYPEDEF_HIDES_STRUCT = YES LOOKUP_CACHE_SIZE = 0 +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -436,13 +498,19 @@ LOOKUP_CACHE_SIZE = 0 # normally produced when WARNINGS is set to YES. # The default value is: NO. -EXTRACT_ALL = YES +EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. -EXTRACT_PRIVATE = YES +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. @@ -454,7 +522,7 @@ EXTRACT_PACKAGE = NO # included in the documentation. # The default value is: NO. -EXTRACT_STATIC = YES +EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, @@ -481,6 +549,13 @@ EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation @@ -498,8 +573,8 @@ HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO, these declarations will be -# included in the documentation. +# declarations. If set to NO, these declarations will be included in the +# documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO @@ -518,21 +593,28 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES, upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. # The default value is: system dependent. -CASE_SENSE_NAMES = NO +CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. -HIDE_SCOPE_NAMES = YES +HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to @@ -541,6 +623,12 @@ HIDE_SCOPE_NAMES = YES HIDE_COMPOUND_REFERENCE= NO +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -649,7 +737,7 @@ GENERATE_DEPRECATEDLIST= YES # sections, marked by \if ... \endif and \cond # ... \endcond blocks. -ENABLED_SECTIONS = +ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the @@ -691,30 +779,31 @@ SHOW_NAMESPACES = YES # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. -LAYOUT_FILE = +LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. -CITE_BIB_FILES = +CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages @@ -725,7 +814,7 @@ CITE_BIB_FILES = # messages are off. # The default value is: NO. -QUIET = YES +QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES @@ -744,23 +833,35 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC # The default value is: NO. -WARN_NO_PARAMDOC = YES +WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. WARN_AS_ERROR = NO @@ -771,15 +872,29 @@ WARN_AS_ERROR = NO # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files @@ -791,13 +906,13 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = ../LibAAF/ +INPUT = @DOXYGEN_INPUT_DIR@ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of -# possible encodings. +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 @@ -810,11 +925,15 @@ INPUT_ENCODING = UTF-8 # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, -# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.cc \ @@ -835,6 +954,7 @@ FILE_PATTERNS = *.c \ *.hxx \ *.hpp \ *.h++ \ + *.l \ *.cs \ *.d \ *.php \ @@ -853,13 +973,14 @@ FILE_PATTERNS = *.c \ *.f95 \ *.f03 \ *.f08 \ + *.f18 \ *.f \ *.for \ - *.tcl \ *.vhd \ *.vhdl \ *.ucf \ - *.qsf + *.qsf \ + *.ice # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -874,7 +995,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -890,24 +1011,24 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test +# ANamespace::AClass, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and @@ -927,7 +1048,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = +IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -948,7 +1069,7 @@ IMAGE_PATH = # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. -INPUT_FILTER = +INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the @@ -961,7 +1082,7 @@ INPUT_FILTER = # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. -FILTER_PATTERNS = +FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for @@ -976,14 +1097,14 @@ FILTER_SOURCE_FILES = NO # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. -FILTER_SOURCE_PATTERNS = +FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = @DOXYGEN_USE_MDFILE_AS_MAINPAGE@ #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -996,7 +1117,7 @@ USE_MDFILE_AS_MAINPAGE = # also VERBATIM_HEADERS is set to NO. # The default value is: NO. -SOURCE_BROWSER = YES +SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. @@ -1012,10 +1133,10 @@ INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. +# entity all documented functions referencing it will be listed. # The default value is: NO. -REFERENCED_BY_RELATION = YES +REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. @@ -1044,12 +1165,12 @@ SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version +# (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # @@ -1072,23 +1193,44 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the -# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the -# cost of reduced performance. This can be particularly helpful with template -# rich C++ code for which doxygen's built-in parser lacks the necessary type -# information. +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. # Note: The availability of this option depends on whether or not doxygen was -# generated with the -Duse-libclang=ON option for CMake. +# generated with the -Duse_libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. +# The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_ADD_INC_PATHS = YES + # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. -CLANG_OPTIONS = +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index @@ -1101,20 +1243,13 @@ CLANG_OPTIONS = ALPHABETICAL_INDEX = YES -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output @@ -1158,7 +1293,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = ../doc/theme/header.html # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1168,7 +1303,7 @@ HTML_HEADER = # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = +HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of @@ -1180,7 +1315,7 @@ HTML_FOOTER = # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_STYLESHEET = +HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets @@ -1193,7 +1328,7 @@ HTML_STYLESHEET = # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = ./style.css +HTML_EXTRA_STYLESHEET = ../doc/theme/doxygen-awesome.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1203,12 +1338,12 @@ HTML_EXTRA_STYLESHEET = ./style.css # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = ../doc/doxygen-awesome/doxygen-awesome-darkmode-toggle.js # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. @@ -1217,7 +1352,7 @@ HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A +# in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1244,6 +1379,17 @@ HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = NO +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. @@ -1267,13 +1413,14 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1287,6 +1434,13 @@ GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. @@ -1312,8 +1466,12 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1332,7 +1490,7 @@ GENERATE_HTMLHELP = NO # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_FILE = +CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, @@ -1340,10 +1498,10 @@ CHM_FILE = # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -HHC_LOCATION = +HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the master .chm file (NO). +# (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1353,7 +1511,7 @@ GENERATE_CHI = NO # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_INDEX_ENCODING = +CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it @@ -1384,11 +1542,12 @@ GENERATE_QHP = NO # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. -QCH_FILE = +QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1396,8 +1555,8 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1405,33 +1564,33 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_ATTRS = +QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_SECT_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. -QHG_LOCATION = +QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To @@ -1471,15 +1630,27 @@ DISABLE_INDEX = NO # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = NO +GENERATE_TREEVIEW = YES + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. @@ -1505,6 +1676,24 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML @@ -1514,7 +1703,7 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # @@ -1525,8 +1714,14 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1536,11 +1731,29 @@ FORMULA_TRANSPARENT = YES USE_MATHJAX = NO +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + # When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1553,26 +1766,33 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_EXTENSIONS = +MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_CODEFILE = +MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and @@ -1596,7 +1816,7 @@ MATHJAX_CODEFILE = SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using Javascript. There +# implemented using a web server instead of a web client using JavaScript. There # are two flavors of web server based searching depending on the EXTERNAL_SEARCH # setting. When disabled, doxygen will generate a PHP script for searching and # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing @@ -1615,7 +1835,8 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: +# https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1628,11 +1849,12 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and -# Searching" for details. +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. # This tag requires that the tag SEARCHENGINE is set to YES. -SEARCHENGINE_URL = +SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the @@ -1648,7 +1870,7 @@ SEARCHDATA_FILE = searchdata.xml # projects and redirect the results back to the right project. # This tag requires that the tag SEARCHENGINE is set to YES. -EXTERNAL_SEARCH_ID = +EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are @@ -1658,7 +1880,7 @@ EXTERNAL_SEARCH_ID = # EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... # This tag requires that the tag SEARCHENGINE is set to YES. -EXTRA_SEARCH_MAPPINGS = +EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output @@ -1667,7 +1889,7 @@ EXTRA_SEARCH_MAPPINGS = # If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # The default value is: YES. -GENERATE_LATEX = NO +GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1680,21 +1902,35 @@ LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. # -# Note that when enabling USE_PDFLATEX this option is only used for generating -# bitmaps for formulas in the HTML output, but not in the Makefile that is -# written to the output directory. -# The default file is: latex. +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_CMD_NAME = latex +LATEX_CMD_NAME = # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. MAKEINDEX_CMD_NAME = makeindex +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = makeindex + # If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. @@ -1722,34 +1958,36 @@ PAPER_TYPE = a4 # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. -EXTRA_PACKAGES = +EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the -# generated LaTeX document. The header should contain everything until the first -# chapter. If it is left blank doxygen will generate a standard header. See -# section "Doxygen usage" for information on how to let doxygen write the -# default header to a separate file. +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. # -# Note: Only use a user-defined header if you know what you are doing! The -# following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empty -# string, for the replacement values of the other commands the user is referred -# to HTML_HEADER. +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_HEADER = +LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the -# generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. See +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what -# special commands can be used inside the footer. -# -# Note: Only use a user-defined footer if you know what you are doing! +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_FOOTER = +LATEX_FOOTER = # The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined # LaTeX style sheets that are included after the standard style sheets created @@ -1760,7 +1998,7 @@ LATEX_FOOTER = # list). # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_STYLESHEET = # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output @@ -1768,7 +2006,7 @@ LATEX_EXTRA_STYLESHEET = # markers available. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_EXTRA_FILES = +LATEX_EXTRA_FILES = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is # prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will @@ -1779,9 +2017,11 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES, to get a -# higher quality PDF documentation. +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1789,8 +2029,7 @@ USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode # command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. This option is also used -# when generating formulas in HTML. +# if errors occur, instead of asking the user for help. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1803,19 +2042,9 @@ LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO -# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source -# code with syntax highlighting in the LaTeX output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_SOURCE_CODE = NO - # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1829,6 +2058,14 @@ LATEX_BIB_STYLE = plain LATEX_TIMESTAMP = NO +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- @@ -1868,32 +2105,22 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's config -# file, i.e. a series of assignments. You only have to provide replacements, -# missing definitions are set to their default value. +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. # # See also section "Doxygen usage" for information on how to generate the # default style sheet that doxygen normally uses. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is -# similar to doxygen's config file. A template extensions file can be generated -# using doxygen -e rtf extensionFile. -# This tag requires that the tag GENERATE_RTF is set to YES. - -RTF_EXTENSIONS_FILE = - -# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code -# with syntax highlighting in the RTF output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_SOURCE_CODE = NO +RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # Configuration options related to the man page output @@ -1903,7 +2130,7 @@ RTF_SOURCE_CODE = NO # classes and files. # The default value is: NO. -GENERATE_MAN = YES +GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1928,7 +2155,7 @@ MAN_EXTENSION = .3 # MAN_EXTENSION with the initial . removed. # This tag requires that the tag GENERATE_MAN is set to YES. -MAN_SUBDIR = +MAN_SUBDIR = # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real @@ -1966,6 +2193,13 @@ XML_OUTPUT = xml XML_PROGRAMLISTING = YES +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- @@ -1984,23 +2218,14 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook -# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the -# program listings (including syntax highlighting and cross-referencing -# information) to the DOCBOOK output. Note that enabling this will significantly -# increase the size of the DOCBOOK output. -# The default value is: NO. -# This tag requires that the tag GENERATE_DOCBOOK is set to YES. - -DOCBOOK_PROGRAMLISTING = NO - #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sf.net) file that captures the -# structure of the code including all documentation. Note that this feature is -# still experimental and incomplete at the moment. +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO @@ -2041,7 +2266,7 @@ PERLMOD_PRETTY = YES # overwrite each other's variables. # This tag requires that the tag GENERATE_PERLMOD is set to YES. -PERLMOD_MAKEVAR_PREFIX = +PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor @@ -2060,7 +2285,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = YES +MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -2068,7 +2293,7 @@ MACRO_EXPANSION = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_ONLY_PREDEF = YES +EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. @@ -2079,10 +2304,11 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = +INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the @@ -2090,7 +2316,7 @@ INCLUDE_PATH = # used. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that are # defined before the preprocessor is started (similar to the -D option of e.g. @@ -2100,7 +2326,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = __attribute__((packed))= +PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -2109,7 +2335,7 @@ PREDEFINED = __attribute__((packed))= # definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_AS_DEFINED = WAVEFORMAT_HEAD +EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will # remove all references to function-like macros that are alone on a line, have @@ -2138,13 +2364,13 @@ SKIP_FUNCTION_MACROS = YES # the path). If a tag file is not located in the directory in which doxygen is # run, you must also specify the path to the tagfile here. -TAGFILES = +TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create a # tag file that is based on the input files it reads. See section "Linking to # external documentation" for more information about the usage of tag files. -GENERATE_TAGFILE = +GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES, all external class will be listed in # the class index. If set to NO, only the inherited external classes will be @@ -2167,40 +2393,16 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram -# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to -# NO turns the diagrams off. Note that this option also works with HAVE_DOT -# disabled, but it is recommended to install and use dot, since it yields more -# powerful graphs. -# The default value is: YES. - -CLASS_DIAGRAMS = NO - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. # If left empty dia is assumed to be found in the default search path. -DIA_PATH = +DIA_PATH = # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. @@ -2249,13 +2451,16 @@ DOT_FONTSIZE = 10 # the path where dot can find it using this tag. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTPATH = +DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a +# graph for each documented class showing the direct and indirect inheritance +# relations. In case HAVE_DOT is set as well dot will be used to draw the graph, +# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set +# to TEXT the direct and indirect inheritance relations will be shown as texts / +# links. +# Possible values are: NO, YES, TEXT and GRAPH. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES @@ -2269,7 +2474,8 @@ CLASS_GRAPH = YES COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. See also the chapter Grouping +# in the manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2292,10 +2498,32 @@ UML_LOOK = NO # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. +# This tag requires that the tag UML_LOOK is set to YES. UML_LIMIT_NUM_FIELDS = 10 +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will wrapped across multiple lines. Some heuristics are apply +# to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their # instances. @@ -2311,7 +2539,7 @@ TEMPLATE_RELATIONS = NO # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -INCLUDE_GRAPH = NO +INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing @@ -2320,7 +2548,7 @@ INCLUDE_GRAPH = NO # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -INCLUDED_BY_GRAPH = NO +INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH tag is set to YES then doxygen will generate a call # dependency graph for every global function or class method. @@ -2351,7 +2579,7 @@ CALLER_GRAPH = NO # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -GRAPHICAL_HIERARCHY = NO +GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The @@ -2362,6 +2590,13 @@ GRAPHICAL_HIERARCHY = NO DIRECTORY_GRAPH = YES +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: @@ -2369,10 +2604,9 @@ DIRECTORY_GRAPH = YES # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). -# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, -# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo, -# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo, -# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# Possible values are: png, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, +# gif, gif:cairo, gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, +# png:cairo, png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and # png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2395,44 +2629,44 @@ INTERACTIVE_SVG = NO # found. If left blank, it is assumed the dot tool can be found in the path. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_PATH = +DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the \dotfile # command). # This tag requires that the tag HAVE_DOT is set to YES. -DOTFILE_DIRS = +DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the \mscfile # command). -MSCFILE_DIRS = +MSCFILE_DIRS = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile # command). -DIAFILE_DIRS = +DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the -# path where java can find the plantuml.jar file. If left blank, it is assumed -# PlantUML is not used or called during a preprocessing step. Doxygen will -# generate a warning when it encounters a \startuml command in this case and -# will not generate output for the diagram. +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. -PLANTUML_JAR_PATH = +PLANTUML_JAR_PATH = # When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a # configuration file for plantuml. -PLANTUML_CFG_FILE = +PLANTUML_CFG_FILE = # When using plantuml, the specified paths are searched for files specified by # the !include statement in a plantuml block. -PLANTUML_INCLUDE_PATH = +PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes @@ -2482,14 +2716,18 @@ DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc temporary +# files. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES diff --git a/doc/style.css b/doc/style.css deleted file mode 100644 index b51b2f4..0000000 --- a/doc/style.css +++ /dev/null @@ -1,228 +0,0 @@ - -body { - color: rgb(51,51,51); -} - -div.contents -{ - position - margin-top: 10px; - margin-left: auto; - margin-right: auto; - max-width: 1200px; - border: 1px solid #ccc; - padding: 15px; -} - -.contents a, -.contents a:visited, -.contents a:active, -.contents a:link -{ - color: #3498db !important; - text-decoration: none; - text-shadow: none; -} - -.contents a:hover, -.contents a:focus -{ - color: #78b4dd !important; -} - -h1.groupheader -{} - -h2 -{ - color: inherit; - font-weight: 200 !important; - font-size: 34px; - border-bottom: none; - margin-top: 22px; - margin-bottom: 11px; - line-height: 1.1; - margin-left: none; - padding-left: none; -} - -h3.groupheader, -h4.groupheader, -h5.groupheader, -h6.groupheader -{ -/* - color: inherit; - font-size: inherit; - font-weight: inherit; - text-decoration: inherit; -*/ -} - -h2.memtitle -{ - display: none; -} - -.memproto, -dl.reflist dt -{ - background: #f5f5f5; -/* -webkit-border-top-left-radius: 4px;*/ - -webkit-border-radius: none; -} - -table.memname -{ - border-collapse: collapse; -} - -table.memname td -{ - padding-top: 0; - padding-bottom: 0; -} - -.memdoc, -/*.memdoc p, */ -.memdoc p.definition, -.memdoc p.reference, -.memdoc dl -{ - font-size: 0.8rem; -} - -.memdoc p.definition, -.memdoc p.reference -{ - margin-bottom: 0; - color: rgb(151, 151, 151); -} - -.memdoc -{ - padding: 32px 10px 10px 10px; - margin-bottom: 22px; -} - -.memdoc p.reference a, -.memdoc p.definition a -{ - color: #97adbc !important; -} - - -p -{ - margin: 0 0 11px; -} - - - - -hr -{ - margin-top: 22px; - margin-bottom: 22px; - border: 0; - border-top: 1px solid #eee; -} - - - - - - -div.fragment -{ - padding-left: 6px; - padding-right: 6px; - padding-top: 8px; - padding-bottom: 5px; -} -div.line -{ - padding-bottom: 3px; -} - - - - - - - - - -.tabsearch { -/* - background-image: url('tab_b.png'); - background-image: none; -*/ - background: none; -} - -.navpath ul -{ -/* - background-image:url('tab_b.png'); - background-repeat:repeat-x; - background-position: 0 -5px; -*/ - background: none; - background-color: #E6E6E6; -} - -.sm-dox -{ - background: none; - background-color: #222; -} - -.sm-dox a, -.sm-dox a:focus, -.sm-dox a:active, -.sm-dox a:hover, -.sm-dox a:visited -{ - background: none; - color: #f2f2f2; - text-decoration: none; - text-shadow: none; - font-weight: normal; -/* font: 400 Roboto,sans-serif; */ -} - -.sm-dox a:hover, -.sm-dox a.highlighted -{ - color: #1abc9c; - background: none; -} - -.sm-dox a span.sub-arrow -{ - border-color: #f2f2f2 transparent transparent transparent; -} - -.sm-dox a.highlighted span.sub-arrow -{ - border-color: #1abc9c transparent transparent transparent; -} - -.sm-dox ul a, -.sm-dox ul a:focus, -.sm-dox ul a:active, -.sm-dox ul a:hover, -.sm-dox ul a:visited -{ - color: rgb(51, 51, 51); - background: none; - text-shadow: none; -} - -.sm-dox ul a:focus, -.sm-dox ul a:hover, -.sm-dox ul a.highlighted -{ - color: #1abc9c; -} diff --git a/doc/theme/doxygen-awesome.css b/doc/theme/doxygen-awesome.css new file mode 100644 index 0000000..7a6b489 --- /dev/null +++ b/doc/theme/doxygen-awesome.css @@ -0,0 +1,2669 @@ +/** + +Doxygen Awesome +https://github.com/jothepro/doxygen-awesome-css + +MIT License + +Copyright (c) 2021 - 2023 jothepro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +html { + /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */ + --primary-color: #1779c4; + --primary-dark-color: #335c80; + --primary-light-color: #70b1e9; + + /* page base colors */ + --page-background-color: #ffffff; + --page-foreground-color: #2f4153; + --page-secondary-foreground-color: #6f7e8e; + + /* color for all separators on the website: hr, borders, ... */ + --separator-color: #dedede; + + /* border radius for all rounded components. Will affect many components, like dropdowns, memitems, codeblocks, ... */ + --border-radius-large: 8px; + --border-radius-small: 4px; + --border-radius-medium: 6px; + + /* default spacings. Most components reference these values for spacing, to provide uniform spacing on the page. */ + --spacing-small: 5px; + --spacing-medium: 10px; + --spacing-large: 16px; + + /* default box shadow used for raising an element above the normal content. Used in dropdowns, search result, ... */ + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.075); + + --odd-color: rgba(0,0,0,.028); + + /* font-families. will affect all text on the website + * font-family: the normal font for text, headlines, menus + * font-family-monospace: used for preformatted text in memtitle, code, fragments + */ + --font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif; + --font-family-monospace: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; + + /* font sizes */ + --page-font-size: 15.6px; + --navigation-font-size: 14.4px; + --toc-font-size: 13.4px; + --code-font-size: 14px; /* affects code, fragment */ + --title-font-size: 22px; + + /* content text properties. These only affect the page content, not the navigation or any other ui elements */ + --content-line-height: 27px; + /* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/ + --content-maxwidth: 1050px; + --table-line-height: 24px; + --toc-sticky-top: var(--spacing-medium); + --toc-width: 200px; + --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 85px); + + /* colors for various content boxes: @warning, @note, @deprecated @bug */ + --warning-color: #faf3d8; + --warning-color-dark: #f3a600; + --warning-color-darker: #5f4204; + --note-color: #e4f3ff; + --note-color-dark: #1879C4; + --note-color-darker: #274a5c; + --todo-color: #e4dafd; + --todo-color-dark: #5b2bdd; + --todo-color-darker: #2a0d72; + --deprecated-color: #ecf0f3; + --deprecated-color-dark: #5b6269; + --deprecated-color-darker: #43454a; + --bug-color: #f8d1cc; + --bug-color-dark: #b61825; + --bug-color-darker: #75070f; + --invariant-color: #d8f1e3; + --invariant-color-dark: #44b86f; + --invariant-color-darker: #265532; + + /* blockquote colors */ + --blockquote-background: #f8f9fa; + --blockquote-foreground: #636568; + + /* table colors */ + --tablehead-background: #f1f1f1; + --tablehead-foreground: var(--page-foreground-color); + + /* menu-display: block | none + * Visibility of the top navigation on screens >= 768px. On smaller screen the menu is always visible. + * `GENERATE_TREEVIEW` MUST be enabled! + */ + --menu-display: block; + + --menu-focus-foreground: var(--page-background-color); + --menu-focus-background: var(--primary-color); + --menu-selected-background: rgba(0,0,0,.05); + + + --header-background: var(--page-background-color); + --header-foreground: var(--page-foreground-color); + + /* searchbar colors */ + --searchbar-background: var(--side-nav-background); + --searchbar-foreground: var(--page-foreground-color); + + /* searchbar size + * (`searchbar-width` is only applied on screens >= 768px. + * on smaller screens the searchbar will always fill the entire screen width) */ + --searchbar-height: 33px; + --searchbar-width: 210px; + --searchbar-border-radius: var(--searchbar-height); + + /* code block colors */ + --code-background: #f5f5f5; + --code-foreground: var(--page-foreground-color); + + /* fragment colors */ + --fragment-background: #F8F9FA; + --fragment-foreground: #37474F; + --fragment-keyword: #bb6bb2; + --fragment-keywordtype: #8258b3; + --fragment-keywordflow: #d67c3b; + --fragment-token: #438a59; + --fragment-comment: #969696; + --fragment-link: #5383d6; + --fragment-preprocessor: #46aaa5; + --fragment-linenumber-color: #797979; + --fragment-linenumber-background: #f4f4f5; + --fragment-linenumber-border: #e3e5e7; + --fragment-lineheight: 20px; + + /* sidebar navigation (treeview) colors */ + --side-nav-background: #fbfbfb; + --side-nav-foreground: var(--page-foreground-color); + --side-nav-arrow-opacity: 0; + --side-nav-arrow-hover-opacity: 0.9; + + --toc-background: var(--side-nav-background); + --toc-foreground: var(--side-nav-foreground); + + /* height of an item in any tree / collapsible table */ + --tree-item-height: 30px; + + --memname-font-size: var(--code-font-size); + --memtitle-font-size: 18px; + + --webkit-scrollbar-size: 7px; + --webkit-scrollbar-padding: 4px; + --webkit-scrollbar-color: var(--separator-color); + + --animation-duration: .12s +} + +@media screen and (max-width: 767px) { + html { + --page-font-size: 16px; + --navigation-font-size: 16px; + --toc-font-size: 15px; + --code-font-size: 15px; /* affects code, fragment */ + --title-font-size: 22px; + } +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) { + color-scheme: dark; + + --primary-color: #1982d2; + --primary-dark-color: #86a9c4; + --primary-light-color: #4779ac; + + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.35); + + --odd-color: rgba(100,100,100,.06); + + --menu-selected-background: rgba(0,0,0,.4); + + --page-background-color: #1C1D1F; + --page-foreground-color: #d2dbde; + --page-secondary-foreground-color: #859399; + --separator-color: #38393b; + --side-nav-background: #252628; + + --code-background: #2a2c2f; + + --tablehead-background: #2a2c2f; + + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #3b2e04; + --warning-color-dark: #f1b602; + --warning-color-darker: #ceb670; + --note-color: #163750; + --note-color-dark: #1982D2; + --note-color-darker: #dcf0fa; + --todo-color: #2a2536; + --todo-color-dark: #7661b3; + --todo-color-darker: #ae9ed6; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2e1917; + --bug-color-dark: #ad2617; + --bug-color-darker: #f5b1aa; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; + } +} + +/* dark mode variables are defined twice, to support both the dark-mode without and with doxygen-awesome-darkmode-toggle.js */ +html.dark-mode { + color-scheme: dark; + + --primary-color: #1982d2; + --primary-dark-color: #86a9c4; + --primary-light-color: #4779ac; + + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.30); + + --odd-color: rgba(100,100,100,.06); + + --menu-selected-background: rgba(0,0,0,.4); + + --page-background-color: #1C1D1F; + --page-foreground-color: #d2dbde; + --page-secondary-foreground-color: #859399; + --separator-color: #38393b; + --side-nav-background: #252628; + + --code-background: #2a2c2f; + + --tablehead-background: #2a2c2f; + + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #3b2e04; + --warning-color-dark: #f1b602; + --warning-color-darker: #ceb670; + --note-color: #163750; + --note-color-dark: #1982D2; + --note-color-darker: #dcf0fa; + --todo-color: #2a2536; + --todo-color-dark: #7661b3; + --todo-color-darker: #ae9ed6; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2e1917; + --bug-color-dark: #ad2617; + --bug-color-darker: #f5b1aa; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; +} + +body { + color: var(--page-foreground-color); + background-color: var(--page-background-color); + font-size: var(--page-font-size); +} + +body, table, div, p, dl, #nav-tree .label, .title, +.sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, +.SelectItem, #MSearchField, .navpath li.navelem a, +.navpath li.navelem a:hover, p.reference, p.definition, div.toc li, div.toc h3 { + font-family: var(--font-family); +} + +h1, h2, h3, h4, h5 { + margin-top: 1em; + font-weight: 600; + line-height: initial; +} + +p, div, table, dl, p.reference, p.definition { + font-size: var(--page-font-size); +} + +p.reference, p.definition { + color: var(--page-secondary-foreground-color); +} + +a:link, a:visited, a:hover, a:focus, a:active { + color: var(--primary-color) !important; + font-weight: 500; +} + +a.anchor { + scroll-margin-top: var(--spacing-large); + display: block; +} + +/* + Title and top navigation + */ + +#top { + background: var(--header-background); + border-bottom: 1px solid var(--separator-color); +} + +@media screen and (min-width: 768px) { + #top { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + } +} + +#main-nav { + flex-grow: 5; + padding: var(--spacing-small) var(--spacing-medium); +} + +#titlearea { + width: auto; + padding: var(--spacing-medium) var(--spacing-large); + background: none; + color: var(--header-foreground); + border-bottom: none; +} + +@media screen and (max-width: 767px) { + #titlearea { + padding-bottom: var(--spacing-small); + } +} + +#titlearea table tbody tr { + height: auto !important; +} + +#projectname { + font-size: var(--title-font-size); + font-weight: 600; +} + +#projectnumber { + font-family: inherit; + font-size: 60%; +} + +#projectbrief { + font-family: inherit; + font-size: 80%; +} + +#projectlogo { + vertical-align: middle; +} + +#projectlogo img { + max-height: calc(var(--title-font-size) * 2); + margin-right: var(--spacing-small); +} + +.sm-dox, .tabs, .tabs2, .tabs3 { + background: none; + padding: 0; +} + +.tabs, .tabs2, .tabs3 { + border-bottom: 1px solid var(--separator-color); + margin-bottom: -1px; +} + +.main-menu-btn-icon, .main-menu-btn-icon:before, .main-menu-btn-icon:after { + background: var(--page-secondary-foreground-color); +} + +@media screen and (max-width: 767px) { + .sm-dox a span.sub-arrow { + background: var(--code-background); + } + + #main-menu a.has-submenu span.sub-arrow { + color: var(--page-secondary-foreground-color); + border-radius: var(--border-radius-medium); + } + + #main-menu a.has-submenu:hover span.sub-arrow { + color: var(--page-foreground-color); + } +} + +@media screen and (min-width: 768px) { + .sm-dox li, .tablist li { + display: var(--menu-display); + } + + .sm-dox a span.sub-arrow { + border-color: var(--header-foreground) transparent transparent transparent; + } + + .sm-dox a:hover span.sub-arrow { + border-color: var(--menu-focus-foreground) transparent transparent transparent; + } + + .sm-dox ul a span.sub-arrow { + border-color: transparent transparent transparent var(--page-foreground-color); + } + + .sm-dox ul a:hover span.sub-arrow { + border-color: transparent transparent transparent var(--menu-focus-foreground); + } +} + +.sm-dox ul { + background: var(--page-background-color); + box-shadow: var(--box-shadow); + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium) !important; + padding: var(--spacing-small); + animation: ease-out 150ms slideInMenu; +} + +@keyframes slideInMenu { + from { + opacity: 0; + transform: translate(0px, -2px); + } + + to { + opacity: 1; + transform: translate(0px, 0px); + } +} + +.sm-dox ul a { + color: var(--page-foreground-color) !important; + background: var(--page-background-color); + font-size: var(--navigation-font-size); +} + +.sm-dox>li>ul:after { + border-bottom-color: var(--page-background-color) !important; +} + +.sm-dox>li>ul:before { + border-bottom-color: var(--separator-color) !important; +} + +.sm-dox ul a:hover, .sm-dox ul a:active, .sm-dox ul a:focus { + font-size: var(--navigation-font-size) !important; + color: var(--menu-focus-foreground) !important; + text-shadow: none; + background-color: var(--menu-focus-background); + border-radius: var(--border-radius-small) !important; +} + +.sm-dox a, .sm-dox a:focus, .tablist li, .tablist li a, .tablist li.current a { + text-shadow: none; + background: transparent; + background-image: none !important; + color: var(--header-foreground) !important; + font-weight: normal; + font-size: var(--navigation-font-size); + border-radius: var(--border-radius-small) !important; +} + +.sm-dox a:focus { + outline: auto; +} + +.sm-dox a:hover, .sm-dox a:active, .tablist li a:hover { + text-shadow: none; + font-weight: normal; + background: var(--menu-focus-background); + color: var(--menu-focus-foreground) !important; + border-radius: var(--border-radius-small) !important; + font-size: var(--navigation-font-size); +} + +.tablist li.current { + border-radius: var(--border-radius-small); + background: var(--menu-selected-background); +} + +.tablist li { + margin: var(--spacing-small) 0 var(--spacing-small) var(--spacing-small); +} + +.tablist a { + padding: 0 var(--spacing-large); +} + + +/* + Search box + */ + +#MSearchBox { + height: var(--searchbar-height); + background: var(--searchbar-background); + border-radius: var(--searchbar-border-radius); + border: 1px solid var(--separator-color); + overflow: hidden; + width: var(--searchbar-width); + position: relative; + box-shadow: none; + display: block; + margin-top: 0; +} + +/* until Doxygen 1.9.4 */ +.left img#MSearchSelect { + left: 0; + user-select: none; + padding-left: 8px; +} + +/* Doxygen 1.9.5 */ +.left span#MSearchSelect { + left: 0; + user-select: none; + margin-left: 8px; + padding: 0; +} + +.left #MSearchSelect[src$=".png"] { + padding-left: 0 +} + +.SelectionMark { + user-select: none; +} + +.tabs .left #MSearchSelect { + padding-left: 0; +} + +.tabs #MSearchBox { + position: absolute; + right: var(--spacing-medium); +} + +@media screen and (max-width: 767px) { + .tabs #MSearchBox { + position: relative; + right: 0; + margin-left: var(--spacing-medium); + margin-top: 0; + } +} + +#MSearchSelectWindow, #MSearchResultsWindow { + z-index: 9999; +} + +#MSearchBox.MSearchBoxActive { + border-color: var(--primary-color); + box-shadow: inset 0 0 0 1px var(--primary-color); +} + +#main-menu > li:last-child { + margin-right: 0; +} + +@media screen and (max-width: 767px) { + #main-menu > li:last-child { + height: 50px; + } +} + +#MSearchField { + font-size: var(--navigation-font-size); + height: calc(var(--searchbar-height) - 2px); + background: transparent; + width: calc(var(--searchbar-width) - 64px); +} + +.MSearchBoxActive #MSearchField { + color: var(--searchbar-foreground); +} + +#MSearchSelect { + top: calc(calc(var(--searchbar-height) / 2) - 11px); +} + +#MSearchBox span.left, #MSearchBox span.right { + background: none; + background-image: none; +} + +#MSearchBox span.right { + padding-top: calc(calc(var(--searchbar-height) / 2) - 12px); + position: absolute; + right: var(--spacing-small); +} + +.tabs #MSearchBox span.right { + top: calc(calc(var(--searchbar-height) / 2) - 12px); +} + +@keyframes slideInSearchResults { + from { + opacity: 0; + transform: translate(0, 15px); + } + + to { + opacity: 1; + transform: translate(0, 20px); + } +} + +#MSearchResultsWindow { + left: auto !important; + right: var(--spacing-medium); + border-radius: var(--border-radius-large); + border: 1px solid var(--separator-color); + transform: translate(0, 20px); + box-shadow: var(--box-shadow); + animation: ease-out 280ms slideInSearchResults; + background: var(--page-background-color); +} + +iframe#MSearchResults { + margin: 4px; +} + +iframe { + color-scheme: normal; +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) iframe#MSearchResults { + filter: invert() hue-rotate(180deg); + } +} + +html.dark-mode iframe#MSearchResults { + filter: invert() hue-rotate(180deg); +} + +#MSearchResults .SRPage { + background-color: transparent; +} + +#MSearchResults .SRPage .SREntry { + font-size: 10pt; + padding: var(--spacing-small) var(--spacing-medium); +} + +#MSearchSelectWindow { + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + box-shadow: var(--box-shadow); + background: var(--page-background-color); + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); +} + +#MSearchSelectWindow a.SelectItem { + font-size: var(--navigation-font-size); + line-height: var(--content-line-height); + margin: 0 var(--spacing-small); + border-radius: var(--border-radius-small); + color: var(--page-foreground-color) !important; + font-weight: normal; +} + +#MSearchSelectWindow a.SelectItem:hover { + background: var(--menu-focus-background); + color: var(--menu-focus-foreground) !important; +} + +@media screen and (max-width: 767px) { + #MSearchBox { + margin-top: var(--spacing-medium); + margin-bottom: var(--spacing-medium); + width: calc(100vw - 30px); + } + + #main-menu > li:last-child { + float: none !important; + } + + #MSearchField { + width: calc(100vw - 110px); + } + + @keyframes slideInSearchResultsMobile { + from { + opacity: 0; + transform: translate(0, 15px); + } + + to { + opacity: 1; + transform: translate(0, 20px); + } + } + + #MSearchResultsWindow { + left: var(--spacing-medium) !important; + right: var(--spacing-medium); + overflow: auto; + transform: translate(0, 20px); + animation: ease-out 280ms slideInSearchResultsMobile; + width: auto !important; + } + + /* + * Overwrites for fixing the searchbox on mobile in doxygen 1.9.2 + */ + label.main-menu-btn ~ #searchBoxPos1 { + top: 3px !important; + right: 6px !important; + left: 45px; + display: flex; + } + + label.main-menu-btn ~ #searchBoxPos1 > #MSearchBox { + margin-top: 0; + margin-bottom: 0; + flex-grow: 2; + float: left; + } +} + +/* + Tree view + */ + +#side-nav { + padding: 0 !important; + background: var(--side-nav-background); + min-width: 8px; + max-width: 50vw; +} + +@media screen and (max-width: 767px) { + #side-nav { + display: none; + } + + #doc-content { + margin-left: 0 !important; + } +} + +#nav-tree { + background: transparent; + margin-right: 1px; +} + +#nav-tree .label { + font-size: var(--navigation-font-size); +} + +#nav-tree .item { + height: var(--tree-item-height); + line-height: var(--tree-item-height); +} + +#nav-sync { + bottom: 12px; + right: 12px; + top: auto !important; + user-select: none; +} + +#nav-tree .selected { + text-shadow: none; + background-image: none; + background-color: transparent; + position: relative; +} + +#nav-tree .selected::after { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + width: 4px; + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + background: var(--primary-color); +} + + +#nav-tree a { + color: var(--side-nav-foreground) !important; + font-weight: normal; +} + +#nav-tree a:focus { + outline-style: auto; +} + +#nav-tree .arrow { + opacity: var(--side-nav-arrow-opacity); +} + +.arrow { + color: inherit; + cursor: pointer; + font-size: 45%; + vertical-align: middle; + margin-right: 2px; + font-family: serif; + height: auto; + text-align: right; +} + +#nav-tree div.item:hover .arrow, #nav-tree a:focus .arrow { + opacity: var(--side-nav-arrow-hover-opacity); +} + +#nav-tree .selected a { + color: var(--primary-color) !important; + font-weight: bolder; + font-weight: 600; +} + +.ui-resizable-e { + width: 4px; + background: transparent; + box-shadow: inset -1px 0 0 0 var(--separator-color); +} + +/* + Contents + */ + +div.header { + border-bottom: 1px solid var(--separator-color); + background-color: var(--page-background-color); + background-image: none; +} + +@media screen and (min-width: 1000px) { + #doc-content > div > div.contents, + .PageDoc > div.contents { + display: flex; + flex-direction: row-reverse; + flex-wrap: nowrap; + align-items: flex-start; + } + + div.contents .textblock { + min-width: 200px; + flex-grow: 1; + } +} + +div.contents, div.header .title, div.header .summary { + max-width: var(--content-maxwidth); +} + +div.contents, div.header .title { + line-height: initial; + margin: calc(var(--spacing-medium) + .2em) auto var(--spacing-medium) auto; +} + +div.header .summary { + margin: var(--spacing-medium) auto 0 auto; +} + +div.headertitle { + padding: 0; +} + +div.header .title { + font-weight: 600; + font-size: 225%; + padding: var(--spacing-medium) var(--spacing-large); + word-break: break-word; +} + +div.header .summary { + width: auto; + display: block; + float: none; + padding: 0 var(--spacing-large); +} + +td.memSeparator { + border-color: var(--separator-color); +} + +span.mlabel { + background: var(--primary-color); + border: none; + padding: 4px 9px; + border-radius: 12px; + margin-right: var(--spacing-medium); +} + +span.mlabel:last-of-type { + margin-right: 2px; +} + +div.contents { + padding: 0 var(--spacing-large); +} + +div.contents p, div.contents li { + line-height: var(--content-line-height); +} + +div.contents div.dyncontent { + margin: var(--spacing-medium) 0; +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) div.contents div.dyncontent img, + html:not(.light-mode) div.contents center img, + html:not(.light-mode) div.contents > table img, + html:not(.light-mode) div.contents div.dyncontent iframe, + html:not(.light-mode) div.contents center iframe, + html:not(.light-mode) div.contents table iframe, + html:not(.light-mode) div.contents .dotgraph iframe { + filter: brightness(89%) hue-rotate(180deg) invert(); + } +} + +html.dark-mode div.contents div.dyncontent img, +html.dark-mode div.contents center img, +html.dark-mode div.contents > table img, +html.dark-mode div.contents div.dyncontent iframe, +html.dark-mode div.contents center iframe, +html.dark-mode div.contents table iframe, +html.dark-mode div.contents .dotgraph iframe + { + filter: brightness(89%) hue-rotate(180deg) invert(); +} + +h2.groupheader { + border-bottom: 0px; + color: var(--page-foreground-color); + box-shadow: + 100px 0 var(--page-background-color), + -100px 0 var(--page-background-color), + 100px 0.75px var(--separator-color), + -100px 0.75px var(--separator-color), + 500px 0 var(--page-background-color), + -500px 0 var(--page-background-color), + 500px 0.75px var(--separator-color), + -500px 0.75px var(--separator-color), + 900px 0 var(--page-background-color), + -900px 0 var(--page-background-color), + 900px 0.75px var(--separator-color), + -900px 0.75px var(--separator-color), + 1400px 0 var(--page-background-color), + -1400px 0 var(--page-background-color), + 1400px 0.75px var(--separator-color), + -1400px 0.75px var(--separator-color), + 1900px 0 var(--page-background-color), + -1900px 0 var(--page-background-color), + 1900px 0.75px var(--separator-color), + -1900px 0.75px var(--separator-color); +} + +blockquote { + margin: 0 var(--spacing-medium) 0 var(--spacing-medium); + padding: var(--spacing-small) var(--spacing-large); + background: var(--blockquote-background); + color: var(--blockquote-foreground); + border-left: 0; + overflow: visible; + border-radius: var(--border-radius-medium); + overflow: visible; + position: relative; +} + +blockquote::before, blockquote::after { + font-weight: bold; + font-family: serif; + font-size: 360%; + opacity: .15; + position: absolute; +} + +blockquote::before { + content: "“"; + left: -10px; + top: 4px; +} + +blockquote::after { + content: "”"; + right: -8px; + bottom: -25px; +} + +blockquote p { + margin: var(--spacing-small) 0 var(--spacing-medium) 0; +} +.paramname { + font-weight: 600; + color: var(--primary-dark-color); +} + +.paramname > code { + border: 0; +} + +table.params .paramname { + font-weight: 600; + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + padding-right: var(--spacing-small); + line-height: var(--table-line-height); +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px var(--primary-light-color); +} + +.alphachar a { + color: var(--page-foreground-color); +} + +.dotgraph { + max-width: 100%; + overflow-x: scroll; +} + +.dotgraph .caption { + position: sticky; + left: 0; +} + +/* Wrap Graphviz graphs with the `interactive_dotgraph` class if `INTERACTIVE_SVG = YES` */ +.interactive_dotgraph .dotgraph iframe { + max-width: 100%; +} + +/* + Table of Contents + */ + +div.contents .toc { + max-height: var(--toc-max-height); + min-width: var(--toc-width); + border: 0; + border-left: 1px solid var(--separator-color); + border-radius: 0; + background-color: transparent; + box-shadow: none; + position: sticky; + top: var(--toc-sticky-top); + padding: 0 var(--spacing-large); + margin: var(--spacing-small) 0 var(--spacing-large) var(--spacing-large); +} + +div.toc h3 { + color: var(--toc-foreground); + font-size: var(--navigation-font-size); + margin: var(--spacing-large) 0 var(--spacing-medium) 0; +} + +div.toc li { + padding: 0; + background: none; + line-height: var(--toc-font-size); + margin: var(--toc-font-size) 0 0 0; +} + +div.toc li::before { + display: none; +} + +div.toc ul { + margin-top: 0 +} + +div.toc li a { + font-size: var(--toc-font-size); + color: var(--page-foreground-color) !important; + text-decoration: none; +} + +div.toc li a:hover, div.toc li a.active { + color: var(--primary-color) !important; +} + +div.toc li a.aboveActive { + color: var(--page-secondary-foreground-color) !important; +} + + +@media screen and (max-width: 999px) { + div.contents .toc { + max-height: 45vh; + float: none; + width: auto; + margin: 0 0 var(--spacing-medium) 0; + position: relative; + top: 0; + position: relative; + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + background-color: var(--toc-background); + box-shadow: var(--box-shadow); + } + + div.contents .toc.interactive { + max-height: calc(var(--navigation-font-size) + 2 * var(--spacing-large)); + overflow: hidden; + } + + div.contents .toc > h3 { + -webkit-tap-highlight-color: transparent; + cursor: pointer; + position: sticky; + top: 0; + background-color: var(--toc-background); + margin: 0; + padding: var(--spacing-large) 0; + display: block; + } + + div.contents .toc.interactive > h3::before { + content: ""; + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + display: inline-block; + margin-right: var(--spacing-small); + margin-bottom: calc(var(--navigation-font-size) / 4); + transform: rotate(-90deg); + transition: transform var(--animation-duration) ease-out; + } + + div.contents .toc.interactive.open > h3::before { + transform: rotate(0deg); + } + + div.contents .toc.interactive.open { + max-height: 45vh; + overflow: auto; + transition: max-height 0.2s ease-in-out; + } + + div.contents .toc a, div.contents .toc a.active { + color: var(--primary-color) !important; + } + + div.contents .toc a:hover { + text-decoration: underline; + } +} + +/* + Code & Fragments + */ + +code, div.fragment, pre.fragment { + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + overflow: hidden; +} + +code { + display: inline; + background: var(--code-background); + color: var(--code-foreground); + padding: 2px 6px; +} + +div.fragment, pre.fragment { + margin: var(--spacing-medium) 0; + padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large); + background: var(--fragment-background); + color: var(--fragment-foreground); + overflow-x: auto; +} + +@media screen and (max-width: 767px) { + div.fragment, pre.fragment { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: 0; + } + + .contents > div.fragment, + .textblock > div.fragment, + .textblock > pre.fragment, + .textblock > .tabbed > ul > li > div.fragment, + .textblock > .tabbed > ul > li > pre.fragment, + .contents > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > pre.fragment, + .textblock > .tabbed > ul > li > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .tabbed > ul > li > .doxygen-awesome-fragment-wrapper > pre.fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-large)); + border-radius: 0; + border-left: 0; + } + + .textblock li > .fragment, + .textblock li > .doxygen-awesome-fragment-wrapper > .fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-large)); + } + + .memdoc li > .fragment, + .memdoc li > .doxygen-awesome-fragment-wrapper > .fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); + } + + .textblock ul, .memdoc ul { + overflow: initial; + } + + .memdoc > div.fragment, + .memdoc > pre.fragment, + dl dd > div.fragment, + dl dd pre.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > div.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > pre.fragment, + dl dd > .doxygen-awesome-fragment-wrapper > div.fragment, + dl dd .doxygen-awesome-fragment-wrapper > pre.fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); + border-radius: 0; + border-left: 0; + } +} + +code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size) !important; +} + +div.line:after { + margin-right: var(--spacing-medium); +} + +div.fragment .line, pre.fragment { + white-space: pre; + word-wrap: initial; + line-height: var(--fragment-lineheight); +} + +div.fragment span.keyword { + color: var(--fragment-keyword); +} + +div.fragment span.keywordtype { + color: var(--fragment-keywordtype); +} + +div.fragment span.keywordflow { + color: var(--fragment-keywordflow); +} + +div.fragment span.stringliteral { + color: var(--fragment-token) +} + +div.fragment span.comment { + color: var(--fragment-comment); +} + +div.fragment a.code { + color: var(--fragment-link) !important; +} + +div.fragment span.preprocessor { + color: var(--fragment-preprocessor); +} + +div.fragment span.lineno { + display: inline-block; + width: 27px; + border-right: none; + background: var(--fragment-linenumber-background); + color: var(--fragment-linenumber-color); +} + +div.fragment span.lineno a { + background: none; + color: var(--fragment-link) !important; +} + +div.fragment > .line:first-child .lineno { + box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border); + background-color: var(--fragment-linenumber-background) !important; +} + +div.line { + border-radius: var(--border-radius-small); +} + +div.line.glow { + background-color: var(--primary-light-color); + box-shadow: none; +} + +/* + dl warning, attention, note, deprecated, bug, ... + */ + +dl.bug dt a, dl.deprecated dt a, dl.todo dt a { + font-weight: bold !important; +} + +dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.post, dl.todo, dl.remark { + padding: var(--spacing-medium); + margin: var(--spacing-medium) 0; + color: var(--page-background-color); + overflow: hidden; + margin-left: 0; + border-radius: var(--border-radius-small); +} + +dl.section dd { + margin-bottom: 2px; +} + +dl.warning, dl.attention { + background: var(--warning-color); + border-left: 8px solid var(--warning-color-dark); + color: var(--warning-color-darker); +} + +dl.warning dt, dl.attention dt { + color: var(--warning-color-dark); +} + +dl.note, dl.remark { + background: var(--note-color); + border-left: 8px solid var(--note-color-dark); + color: var(--note-color-darker); +} + +dl.note dt, dl.remark dt { + color: var(--note-color-dark); +} + +dl.todo { + background: var(--todo-color); + border-left: 8px solid var(--todo-color-dark); + color: var(--todo-color-darker); +} + +dl.todo dt a { + color: var(--todo-color-dark) !important; +} + +dl.bug dt a { + color: var(--todo-color-dark) !important; +} + +dl.bug { + background: var(--bug-color); + border-left: 8px solid var(--bug-color-dark); + color: var(--bug-color-darker); +} + +dl.bug dt a { + color: var(--bug-color-dark) !important; +} + +dl.deprecated { + background: var(--deprecated-color); + border-left: 8px solid var(--deprecated-color-dark); + color: var(--deprecated-color-darker); +} + +dl.deprecated dt a { + color: var(--deprecated-color-dark) !important; +} + +dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd { + margin-inline-start: 0px; +} + +dl.invariant, dl.pre, dl.post { + background: var(--invariant-color); + border-left: 8px solid var(--invariant-color-dark); + color: var(--invariant-color-darker); +} + +dl.invariant dt, dl.pre dt, dl.post dt { + color: var(--invariant-color-dark); +} + +/* + memitem + */ + +div.memdoc, div.memproto, h2.memtitle { + box-shadow: none; + background-image: none; + border: none; +} + +div.memdoc { + padding: 0 var(--spacing-medium); + background: var(--page-background-color); +} + +h2.memtitle, div.memitem { + border: 1px solid var(--separator-color); + box-shadow: var(--box-shadow); +} + +h2.memtitle { + box-shadow: 0px var(--spacing-medium) 0 -1px var(--fragment-background), var(--box-shadow); +} + +div.memitem { + transition: none; +} + +div.memproto, h2.memtitle { + background: var(--fragment-background); +} + +h2.memtitle { + font-weight: 500; + font-size: var(--memtitle-font-size); + font-family: var(--font-family-monospace); + border-bottom: none; + border-top-left-radius: var(--border-radius-medium); + border-top-right-radius: var(--border-radius-medium); + word-break: break-all; + position: relative; +} + +h2.memtitle:after { + content: ""; + display: block; + background: var(--fragment-background); + height: var(--spacing-medium); + bottom: calc(0px - var(--spacing-medium)); + left: 0; + right: -14px; + position: absolute; + border-top-right-radius: var(--border-radius-medium); +} + +h2.memtitle > span.permalink { + font-size: inherit; +} + +h2.memtitle > span.permalink > a { + text-decoration: none; + padding-left: 3px; + margin-right: -4px; + user-select: none; + display: inline-block; + margin-top: -6px; +} + +h2.memtitle > span.permalink > a:hover { + color: var(--primary-dark-color) !important; +} + +a:target + h2.memtitle, a:target + h2.memtitle + div.memitem { + border-color: var(--primary-light-color); +} + +div.memitem { + border-top-right-radius: var(--border-radius-medium); + border-bottom-right-radius: var(--border-radius-medium); + border-bottom-left-radius: var(--border-radius-medium); + overflow: hidden; + display: block !important; +} + +div.memdoc { + border-radius: 0; +} + +div.memproto { + border-radius: 0 var(--border-radius-small) 0 0; + overflow: auto; + border-bottom: 1px solid var(--separator-color); + padding: var(--spacing-medium); + margin-bottom: -1px; +} + +div.memtitle { + border-top-right-radius: var(--border-radius-medium); + border-top-left-radius: var(--border-radius-medium); +} + +div.memproto table.memname { + font-family: var(--font-family-monospace); + color: var(--page-foreground-color); + font-size: var(--memname-font-size); + text-shadow: none; +} + +div.memproto div.memtemplate { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--memname-font-size); + margin-left: 2px; + text-shadow: none; +} + +table.mlabels, table.mlabels > tbody { + display: block; +} + +td.mlabels-left { + width: auto; +} + +td.mlabels-right { + margin-top: 3px; + position: sticky; + left: 0; +} + +table.mlabels > tbody > tr:first-child { + display: flex; + justify-content: space-between; + flex-wrap: wrap; +} + +.memname, .memitem span.mlabels { + margin: 0 +} + +/* + reflist + */ + +dl.reflist { + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-medium); + border: 1px solid var(--separator-color); + overflow: hidden; + padding: 0; +} + + +dl.reflist dt, dl.reflist dd { + box-shadow: none; + text-shadow: none; + background-image: none; + border: none; + padding: 12px; +} + + +dl.reflist dt { + font-weight: 500; + border-radius: 0; + background: var(--code-background); + border-bottom: 1px solid var(--separator-color); + color: var(--page-foreground-color) +} + + +dl.reflist dd { + background: none; +} + +/* + Table + */ + +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname), +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { + display: inline-block; + max-width: 100%; +} + +.contents > table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname):not(.classindex) { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); +} + +table.fieldtable, +table.markdownTable tbody, +table.doxtable tbody { + border: none; + margin: var(--spacing-medium) 0; + box-shadow: 0 0 0 1px var(--separator-color); + border-radius: var(--border-radius-small); +} + +table.markdownTable, table.doxtable, table.fieldtable { + padding: 1px; +} + +table.doxtable caption { + display: block; +} + +table.fieldtable { + border-collapse: collapse; + width: 100%; +} + +th.markdownTableHeadLeft, +th.markdownTableHeadRight, +th.markdownTableHeadCenter, +th.markdownTableHeadNone, +table.doxtable th { + background: var(--tablehead-background); + color: var(--tablehead-foreground); + font-weight: 600; + font-size: var(--page-font-size); +} + +th.markdownTableHeadLeft:first-child, +th.markdownTableHeadRight:first-child, +th.markdownTableHeadCenter:first-child, +th.markdownTableHeadNone:first-child, +table.doxtable tr th:first-child { + border-top-left-radius: var(--border-radius-small); +} + +th.markdownTableHeadLeft:last-child, +th.markdownTableHeadRight:last-child, +th.markdownTableHeadCenter:last-child, +th.markdownTableHeadNone:last-child, +table.doxtable tr th:last-child { + border-top-right-radius: var(--border-radius-small); +} + +table.markdownTable td, +table.markdownTable th, +table.fieldtable td, +table.fieldtable th, +table.doxtable td, +table.doxtable th { + border: 1px solid var(--separator-color); + padding: var(--spacing-small) var(--spacing-medium); +} + +table.markdownTable td:last-child, +table.markdownTable th:last-child, +table.fieldtable td:last-child, +table.fieldtable th:last-child, +table.doxtable td:last-child, +table.doxtable th:last-child { + border-right: none; +} + +table.markdownTable td:first-child, +table.markdownTable th:first-child, +table.fieldtable td:first-child, +table.fieldtable th:first-child, +table.doxtable td:first-child, +table.doxtable th:first-child { + border-left: none; +} + +table.markdownTable tr:first-child td, +table.markdownTable tr:first-child th, +table.fieldtable tr:first-child td, +table.fieldtable tr:first-child th, +table.doxtable tr:first-child td, +table.doxtable tr:first-child th { + border-top: none; +} + +table.markdownTable tr:last-child td, +table.markdownTable tr:last-child th, +table.fieldtable tr:last-child td, +table.fieldtable tr:last-child th, +table.doxtable tr:last-child td, +table.doxtable tr:last-child th { + border-bottom: none; +} + +table.markdownTable tr, table.doxtable tr { + border-bottom: 1px solid var(--separator-color); +} + +table.markdownTable tr:last-child, table.doxtable tr:last-child { + border-bottom: none; +} + +.full_width_table table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) { + display: block; +} + +.full_width_table table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { + display: table; + width: 100%; +} + +table.fieldtable th { + font-size: var(--page-font-size); + font-weight: 600; + background-image: none; + background-color: var(--tablehead-background); + color: var(--tablehead-foreground); +} + +table.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fielddoc, .fieldtable th { + border-bottom: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); +} + +table.fieldtable tr:last-child td:first-child { + border-bottom-left-radius: var(--border-radius-small); +} + +table.fieldtable tr:last-child td:last-child { + border-bottom-right-radius: var(--border-radius-small); +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: var(--primary-light-color); + box-shadow: none; +} + +table.memberdecls { + display: block; + -webkit-tap-highlight-color: transparent; +} + +table.memberdecls tr[class^='memitem'] { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); +} + +table.memberdecls tr[class^='memitem'] .memTemplParams { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + color: var(--primary-dark-color); + white-space: normal; +} + +table.memberdecls .memItemLeft, +table.memberdecls .memItemRight, +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight, +table.memberdecls .memTemplParams { + transition: none; + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + background-color: var(--fragment-background); +} + +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight { + padding-top: 2px; +} + +table.memberdecls .memTemplParams { + border-bottom: 0; + border-left: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); + border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; + padding-bottom: var(--spacing-small); +} + +table.memberdecls .memTemplItemLeft { + border-radius: 0 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + border-top: 0; +} + +table.memberdecls .memTemplItemRight { + border-radius: 0 0 var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-left: 0; + border-top: 0; +} + +table.memberdecls .memItemLeft { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + padding-left: var(--spacing-medium); + padding-right: 0; +} + +table.memberdecls .memItemRight { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-right: var(--spacing-medium); + padding-left: 0; + +} + +table.memberdecls .mdescLeft, table.memberdecls .mdescRight { + background: none; + color: var(--page-foreground-color); + padding: var(--spacing-small) 0; +} + +table.memberdecls .memItemLeft, +table.memberdecls .memTemplItemLeft { + padding-right: var(--spacing-medium); +} + +table.memberdecls .memSeparator { + background: var(--page-background-color); + height: var(--spacing-large); + border: 0; + transition: none; +} + +table.memberdecls .groupheader { + margin-bottom: var(--spacing-large); +} + +table.memberdecls .inherit_header td { + padding: 0 0 var(--spacing-medium) 0; + text-indent: -12px; + color: var(--page-secondary-foreground-color); +} + +table.memberdecls img[src="closed.png"], +table.memberdecls img[src="open.png"], +div.dynheader img[src="open.png"], +div.dynheader img[src="closed.png"] { + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + margin-top: 8px; + display: block; + float: left; + margin-left: -10px; + transition: transform var(--animation-duration) ease-out; +} + +table.memberdecls img { + margin-right: 10px; +} + +table.memberdecls img[src="closed.png"], +div.dynheader img[src="closed.png"] { + transform: rotate(-90deg); + +} + +.compoundTemplParams { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--code-font-size); +} + +@media screen and (max-width: 767px) { + + table.memberdecls .memItemLeft, + table.memberdecls .memItemRight, + table.memberdecls .mdescLeft, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemLeft, + table.memberdecls .memTemplItemRight, + table.memberdecls .memTemplParams { + display: block; + text-align: left; + padding-left: var(--spacing-large); + margin: 0 calc(0px - var(--spacing-large)) 0 calc(0px - var(--spacing-large)); + border-right: none; + border-left: none; + border-radius: 0; + white-space: normal; + } + + table.memberdecls .memItemLeft, + table.memberdecls .mdescLeft, + table.memberdecls .memTemplItemLeft { + border-bottom: 0; + padding-bottom: 0; + } + + table.memberdecls .memTemplItemLeft { + padding-top: 0; + } + + table.memberdecls .mdescLeft { + margin-bottom: calc(0px - var(--page-font-size)); + } + + table.memberdecls .memItemRight, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemRight { + border-top: 0; + padding-top: 0; + padding-right: var(--spacing-large); + overflow-x: auto; + } + + table.memberdecls tr[class^='memitem']:not(.inherit) { + display: block; + width: calc(100vw - 2 * var(--spacing-large)); + } + + table.memberdecls .mdescRight { + color: var(--page-foreground-color); + } + + table.memberdecls tr.inherit { + visibility: hidden; + } + + table.memberdecls tr[style="display: table-row;"] { + display: block !important; + visibility: visible; + width: calc(100vw - 2 * var(--spacing-large)); + animation: fade .5s; + } + + @keyframes fade { + 0% { + opacity: 0; + max-height: 0; + } + + 100% { + opacity: 1; + max-height: 200px; + } + } +} + + +/* + Horizontal Rule + */ + +hr { + margin-top: var(--spacing-large); + margin-bottom: var(--spacing-large); + height: 1px; + background-color: var(--separator-color); + border: 0; +} + +.contents hr { + box-shadow: 100px 0 0 var(--separator-color), + -100px 0 0 var(--separator-color), + 500px 0 0 var(--separator-color), + -500px 0 0 var(--separator-color), + 1500px 0 0 var(--separator-color), + -1500px 0 0 var(--separator-color), + 2000px 0 0 var(--separator-color), + -2000px 0 0 var(--separator-color); +} + +.contents img, .contents .center, .contents center, .contents div.image object { + max-width: 100%; + overflow: auto; +} + +@media screen and (max-width: 767px) { + .contents .dyncontent > .center, .contents > center { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); + } +} + +/* + Directories + */ +div.directory { + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + width: auto; +} + +table.directory { + font-family: var(--font-family); + font-size: var(--page-font-size); + font-weight: normal; + width: 100%; +} + +table.directory td.entry, table.directory td.desc { + padding: calc(var(--spacing-small) / 2) var(--spacing-small); + line-height: var(--table-line-height); +} + +table.directory tr.even td:last-child { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; +} + +table.directory tr.even td:first-child { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); +} + +table.directory tr.even:last-child td:last-child { + border-radius: 0 var(--border-radius-small) 0 0; +} + +table.directory tr.even:last-child td:first-child { + border-radius: var(--border-radius-small) 0 0 0; +} + +table.directory td.desc { + min-width: 250px; +} + +table.directory tr.even { + background-color: var(--odd-color); +} + +table.directory tr.odd { + background-color: transparent; +} + +.icona { + width: auto; + height: auto; + margin: 0 var(--spacing-small); +} + +.icon { + background: var(--primary-color); + border-radius: var(--border-radius-small); + font-size: var(--page-font-size); + padding: calc(var(--page-font-size) / 5); + line-height: var(--page-font-size); + transform: scale(0.8); + height: auto; + width: var(--page-font-size); + user-select: none; +} + +.iconfopen, .icondoc, .iconfclosed { + background-position: center; + margin-bottom: 0; + height: var(--table-line-height); +} + +.icondoc { + filter: saturate(0.2); +} + +@media screen and (max-width: 767px) { + div.directory { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + } +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) .iconfopen, html:not(.light-mode) .iconfclosed { + filter: hue-rotate(180deg) invert(); + } +} + +html.dark-mode .iconfopen, html.dark-mode .iconfclosed { + filter: hue-rotate(180deg) invert(); +} + +/* + Class list + */ + +.classindex dl.odd { + background: var(--odd-color); + border-radius: var(--border-radius-small); +} + +.classindex dl.even { + background-color: transparent; +} + +/* + Class Index Doxygen 1.8 +*/ + +table.classindex { + margin-left: 0; + margin-right: 0; + width: 100%; +} + +table.classindex table div.ah { + background-image: none; + background-color: initial; + border-color: var(--separator-color); + color: var(--page-foreground-color); + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-large); + padding: var(--spacing-small); +} + +div.qindex { + background-color: var(--odd-color); + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + padding: var(--spacing-small) 0; +} + +/* + Footer and nav-path + */ + +#nav-path { + width: 100%; +} + +#nav-path ul { + background-image: none; + background: var(--page-background-color); + border: none; + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + border-bottom: 0; + box-shadow: 0 0.75px 0 var(--separator-color); + font-size: var(--navigation-font-size); +} + +img.footer { + width: 60px; +} + +.navpath li.footer { + color: var(--page-secondary-foreground-color); +} + +address.footer { + color: var(--page-secondary-foreground-color); + margin-bottom: var(--spacing-large); +} + +#nav-path li.navelem { + background-image: none; + display: flex; + align-items: center; +} + +.navpath li.navelem a { + text-shadow: none; + display: inline-block; + color: var(--primary-color) !important; +} + +.navpath li.navelem b { + color: var(--primary-dark-color); + font-weight: 500; +} + +li.navelem { + padding: 0; + margin-left: -8px; +} + +li.navelem:first-child { + margin-left: var(--spacing-large); +} + +li.navelem:first-child:before { + display: none; +} + +#nav-path li.navelem:after { + content: ''; + border: 5px solid var(--page-background-color); + border-bottom-color: transparent; + border-right-color: transparent; + border-top-color: transparent; + transform: translateY(-1px) scaleY(4.2); + z-index: 10; + margin-left: 6px; +} + +#nav-path li.navelem:before { + content: ''; + border: 5px solid var(--separator-color); + border-bottom-color: transparent; + border-right-color: transparent; + border-top-color: transparent; + transform: translateY(-1px) scaleY(3.2); + margin-right: var(--spacing-small); +} + +.navpath li.navelem a:hover { + color: var(--primary-color); +} + +/* + Scrollbars for Webkit +*/ + +#nav-tree::-webkit-scrollbar, +div.fragment::-webkit-scrollbar, +pre.fragment::-webkit-scrollbar, +div.memproto::-webkit-scrollbar, +.contents center::-webkit-scrollbar, +.contents .center::-webkit-scrollbar, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar, +div.contents .toc::-webkit-scrollbar, +.contents .dotgraph::-webkit-scrollbar, +.contents .tabs-overview-container::-webkit-scrollbar { + background: transparent; + width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); +} + +#nav-tree::-webkit-scrollbar-thumb, +div.fragment::-webkit-scrollbar-thumb, +pre.fragment::-webkit-scrollbar-thumb, +div.memproto::-webkit-scrollbar-thumb, +.contents center::-webkit-scrollbar-thumb, +.contents .center::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-thumb, +div.contents .toc::-webkit-scrollbar-thumb, +.contents .dotgraph::-webkit-scrollbar-thumb, +.contents .tabs-overview-container::-webkit-scrollbar-thumb { + background-color: transparent; + border: var(--webkit-scrollbar-padding) solid transparent; + border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + background-clip: padding-box; +} + +#nav-tree:hover::-webkit-scrollbar-thumb, +div.fragment:hover::-webkit-scrollbar-thumb, +pre.fragment:hover::-webkit-scrollbar-thumb, +div.memproto:hover::-webkit-scrollbar-thumb, +.contents center:hover::-webkit-scrollbar-thumb, +.contents .center:hover::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody:hover::-webkit-scrollbar-thumb, +div.contents .toc:hover::-webkit-scrollbar-thumb, +.contents .dotgraph:hover::-webkit-scrollbar-thumb, +.contents .tabs-overview-container:hover::-webkit-scrollbar-thumb { + background-color: var(--webkit-scrollbar-color); +} + +#nav-tree::-webkit-scrollbar-track, +div.fragment::-webkit-scrollbar-track, +pre.fragment::-webkit-scrollbar-track, +div.memproto::-webkit-scrollbar-track, +.contents center::-webkit-scrollbar-track, +.contents .center::-webkit-scrollbar-track, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-track, +div.contents .toc::-webkit-scrollbar-track, +.contents .dotgraph::-webkit-scrollbar-track, +.contents .tabs-overview-container::-webkit-scrollbar-track { + background: transparent; +} + +#nav-tree::-webkit-scrollbar-corner { + background-color: var(--side-nav-background); +} + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc { + overflow-x: auto; + overflow-x: overlay; +} + +#nav-tree { + overflow-x: auto; + overflow-y: auto; + overflow-y: overlay; +} + +/* + Scrollbars for Firefox +*/ + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc, +.contents .dotgraph, +.contents .tabs-overview-container { + scrollbar-width: thin; +} + +/* + Optional Dark mode toggle button +*/ + +doxygen-awesome-dark-mode-toggle { + display: inline-block; + margin: 0 0 0 var(--spacing-small); + padding: 0; + width: var(--searchbar-height); + height: var(--searchbar-height); + background: none; + border: none; + border-radius: var(--searchbar-height); + vertical-align: middle; + text-align: center; + line-height: var(--searchbar-height); + font-size: 22px; + display: flex; + align-items: center; + justify-content: center; + user-select: none; + cursor: pointer; +} + +doxygen-awesome-dark-mode-toggle > svg { + transition: transform var(--animation-duration) ease-in-out; +} + +doxygen-awesome-dark-mode-toggle:active > svg { + transform: scale(.5); +} + +doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.03); +} + +html.dark-mode doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.18); +} + +/* + Optional fragment copy button +*/ +.doxygen-awesome-fragment-wrapper { + position: relative; +} + +doxygen-awesome-fragment-copy-button { + opacity: 0; + background: var(--fragment-background); + width: 28px; + height: 28px; + position: absolute; + right: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + top: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + border: 1px solid var(--fragment-foreground); + cursor: pointer; + border-radius: var(--border-radius-small); + display: flex; + justify-content: center; + align-items: center; +} + +.doxygen-awesome-fragment-wrapper:hover doxygen-awesome-fragment-copy-button, doxygen-awesome-fragment-copy-button.success { + opacity: .28; +} + +doxygen-awesome-fragment-copy-button:hover, doxygen-awesome-fragment-copy-button.success { + opacity: 1 !important; +} + +doxygen-awesome-fragment-copy-button:active:not([class~=success]) svg { + transform: scale(.91); +} + +doxygen-awesome-fragment-copy-button svg { + fill: var(--fragment-foreground); + width: 18px; + height: 18px; +} + +doxygen-awesome-fragment-copy-button.success svg { + fill: rgb(14, 168, 14); +} + +doxygen-awesome-fragment-copy-button.success { + border-color: rgb(14, 168, 14); +} + +@media screen and (max-width: 767px) { + .textblock > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .textblock li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + dl dd > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button { + right: 0; + } +} + +/* + Optional paragraph link button +*/ + +a.anchorlink { + font-size: 90%; + margin-left: var(--spacing-small); + color: var(--page-foreground-color) !important; + text-decoration: none; + opacity: .15; + display: none; + transition: opacity var(--animation-duration) ease-in-out, color var(--animation-duration) ease-in-out; +} + +a.anchorlink svg { + fill: var(--page-foreground-color); +} + +h3 a.anchorlink svg, h4 a.anchorlink svg { + margin-bottom: -3px; + margin-top: -4px; +} + +a.anchorlink:hover { + opacity: .45; +} + +h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink { + display: inline-block; +} + +/* + Optional tab feature +*/ + +.tabbed > ul { + padding-inline-start: 0px; + margin: 0; + padding: var(--spacing-small) 0; +} + +.tabbed > ul > li { + display: none; +} + +.tabbed > ul > li.selected { + display: block; +} + +.tabs-overview-container { + overflow-x: auto; + display: block; + overflow-y: visible; +} + +.tabs-overview { + border-bottom: 1px solid var(--separator-color); + display: flex; + flex-direction: row; +} + +@media screen and (max-width: 767px) { + .tabs-overview-container { + margin: 0 calc(0px - var(--spacing-large)); + } + .tabs-overview { + padding: 0 var(--spacing-large) + } +} + +.tabs-overview button.tab-button { + color: var(--page-foreground-color); + margin: 0; + border: none; + background: transparent; + padding: calc(var(--spacing-large) / 2) 0; + display: inline-block; + font-size: var(--page-font-size); + cursor: pointer; + box-shadow: 0 1px 0 0 var(--separator-color); + position: relative; + + -webkit-tap-highlight-color: transparent; +} + +.tabs-overview button.tab-button .tab-title::before { + display: block; + content: attr(title); + font-weight: 600; + height: 0; + overflow: hidden; + visibility: hidden; +} + +.tabs-overview button.tab-button .tab-title { + float: left; + white-space: nowrap; + font-weight: normal; + padding: calc(var(--spacing-large) / 2) var(--spacing-large); + border-radius: var(--border-radius-medium); + transition: background-color var(--animation-duration) ease-in-out, font-weight var(--animation-duration) ease-in-out; +} + +.tabs-overview button.tab-button:not(:last-child) .tab-title { + box-shadow: 8px 0 0 -7px var(--separator-color); +} + +.tabs-overview button.tab-button:hover .tab-title { + background: var(--separator-color); + box-shadow: none; +} + +.tabs-overview button.tab-button.active .tab-title { + font-weight: 600; +} + +.tabs-overview button.tab-button::after { + content: ''; + display: block; + position: absolute; + left: 0; + bottom: 0; + right: 0; + height: 0; + width: 0%; + margin: 0 auto; + border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; + background-color: var(--primary-color); + transition: width var(--animation-duration) ease-in-out, height var(--animation-duration) ease-in-out; +} + +.tabs-overview button.tab-button.active::after { + width: 100%; + box-sizing: border-box; + height: 3px; +} + + +/* + Navigation Buttons +*/ + +.section_buttons:not(:empty) { + margin-top: calc(var(--spacing-large) * 3); +} + +.section_buttons table.markdownTable { + display: block; + width: 100%; +} + +.section_buttons table.markdownTable tbody { + display: table !important; + width: 100%; + box-shadow: none; + border-spacing: 10px; +} + +.section_buttons table.markdownTable td { + padding: 0; +} + +.section_buttons table.markdownTable th { + display: none; +} + +.section_buttons table.markdownTable tr.markdownTableHead { + border: none; +} + +.section_buttons tr th, .section_buttons tr td { + background: none; + border: none; + padding: var(--spacing-large) 0 var(--spacing-small); +} + +.section_buttons a { + display: inline-block; + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + color: var(--page-secondary-foreground-color) !important; + text-decoration: none; + transition: color var(--animation-duration) ease-in-out, background-color var(--animation-duration) ease-in-out; +} + +.section_buttons a:hover { + color: var(--page-foreground-color) !important; + background-color: var(--odd-color); +} + +.section_buttons tr td.markdownTableBodyLeft a { + padding: var(--spacing-medium) var(--spacing-large) var(--spacing-medium) calc(var(--spacing-large) / 2); +} + +.section_buttons tr td.markdownTableBodyRight a { + padding: var(--spacing-medium) calc(var(--spacing-large) / 2) var(--spacing-medium) var(--spacing-large); +} + +.section_buttons tr td.markdownTableBodyLeft a::before, +.section_buttons tr td.markdownTableBodyRight a::after { + color: var(--page-secondary-foreground-color) !important; + display: inline-block; + transition: color .08s ease-in-out, transform .09s ease-in-out; +} + +.section_buttons tr td.markdownTableBodyLeft a::before { + content: '〈'; + padding-right: var(--spacing-large); +} + + +.section_buttons tr td.markdownTableBodyRight a::after { + content: '〉'; + padding-left: var(--spacing-large); +} + + +.section_buttons tr td.markdownTableBodyLeft a:hover::before { + color: var(--page-foreground-color) !important; + transform: translateX(-3px); +} + +.section_buttons tr td.markdownTableBodyRight a:hover::after { + color: var(--page-foreground-color) !important; + transform: translateX(3px); +} + +@media screen and (max-width: 450px) { + .section_buttons a { + width: 100%; + box-sizing: border-box; + } + + .section_buttons tr td:nth-of-type(1).markdownTableBodyLeft a { + border-radius: var(--border-radius-medium) 0 0 var(--border-radius-medium); + border-right: none; + } + + .section_buttons tr td:nth-of-type(2).markdownTableBodyRight a { + border-radius: 0 var(--border-radius-medium) var(--border-radius-medium) 0; + } +} diff --git a/doc/theme/header.html b/doc/theme/header.html new file mode 100644 index 0000000..562e029 --- /dev/null +++ b/doc/theme/header.html @@ -0,0 +1,73 @@ + + + + + + + + +$projectname: $title +$title + + + + + + + + +$treeview +$search +$mathjax + +$extrastylesheet + + + + +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
$projectname $projectnumber +
+
$projectbrief
+
+
$projectbrief
+
$searchbox
$searchbox
+
+ + diff --git a/include/libaaf.h b/include/libaaf.h index ea6364a..26f2f57 100644 --- a/include/libaaf.h +++ b/include/libaaf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -30,13 +30,14 @@ extern "C" { #include #include #include -#include +#include #include #include #include #include +#include #ifdef __cplusplus } diff --git a/include/libaaf/AAFCore.h b/include/libaaf/AAFCore.h index e348cb6..2a74a49 100644 --- a/include/libaaf/AAFCore.h +++ b/include/libaaf/AAFCore.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -128,16 +128,18 @@ typedef struct aafPropertyDefinition aafBoolean_t meta; - wchar_t *name; + char *name; /* * Looks like nobody cares about AAF standard TypeDefinition. All observed files * had incorrect values for Type's Name and Identification, even Avid's files. - * Thus, PDef->type should NOT be trusted + * Thus, PDef->type should NOT be trusted. + * + * TODO: Should be set by attachNewProperty() in AAFClass.c */ - aafUID_t type; // TODO: Should be set by attachNewProperty() in AAFClass.c + aafUID_t type; /** @@ -201,7 +203,7 @@ typedef struct aafclass * A Class is #CONCRETE if it can be retrieved as an * object. Else, a Class is #ABSTRACT if it can't be * directly retrieved and can only be inherited by - * another Class, so only its memebers can be retrieved. + * another Class, so only its members can be retrieved. */ aafBoolean_t isConcrete; @@ -228,7 +230,8 @@ typedef struct aafclass aafBoolean_t meta; - wchar_t *name; // this is set at runtime + /* name is set at runtime */ + char *name; /** @@ -333,10 +336,10 @@ typedef struct aafObject /** - * The name of the Node in the Compound File Tree : cfbNode._ab. + * UTF-8 name of the Node in the Compound File Tree, set from cfbNode._ab. */ - wchar_t Name[CFB_NODE_NAME_SZ]; + char *Name; /** @@ -406,7 +409,8 @@ typedef struct aafObject struct aafObject *nextObj; - struct _aafData *aafd; // only to access aafd->verb + /* keeps track of aafd, mostly to access aafd->verb without having to pass aafd to some functions */ + struct _aafData *aafd; } aafObject; @@ -470,14 +474,14 @@ typedef struct _aafData aafObject *obj; - wchar_t *CompanyName; - wchar_t *ProductName; + char *CompanyName; + char *ProductName; aafProductVersion_t *ProductVersion; - wchar_t *ProductVersionString; + char *ProductVersionString; aafUID_t *ProductID; aafTimeStamp_t *Date; aafProductVersion_t *ToolkitVersion; - wchar_t *Platform; + char *Platform; aafUID_t *GenerationAUID; } Identification; @@ -616,7 +620,7 @@ typedef struct _aafData aafObject *TaggedValueDefinition; - struct dbg *dbg; + struct aafLog *log; } AAF_Data; @@ -672,8 +676,10 @@ typedef struct _aafData */ #define aafRationalToFloat( r ) \ - (( (r).denominator == 0 ) ? 0 : ((float)(r).numerator/(r).denominator)) + (( (r).denominator == 0 ) ? 0 : ((float)(r).numerator/(float)(r).denominator)) +#define aafRationalToDouble( r ) \ + (( (r).denominator == 0 ) ? 0 : ((double)(r).numerator/(r).denominator)) /** * Converts an aafRational_t to a int64 number. @@ -686,6 +692,27 @@ typedef struct _aafData +/** + * Loops through each aafPropertyIndexEntry_t of a "properties" node stream. + * + * @param Header Pointer to the stream's aafPropertyIndexHeader_t struct. + * @param Entry Pointer that will receive each aafPropertyIndexEntry_t struct. + * @param Value Pointer to each property's data value, of aafPropertyIndexEntry_t._length + * bytes length. + * @param i uint32_t iterator. + */ + +#define foreachPropertyEntry( propStream, Header, Entry, Value, valueOffset, i ) \ + for ( valueOffset = sizeof(aafPropertyIndexHeader_t) + (Header._entryCount * sizeof(aafPropertyIndexEntry_t)), \ + i = 0; \ + i < Header._entryCount && \ + memcpy( &Entry, (propStream + ((sizeof(aafPropertyIndexHeader_t)) + (sizeof(aafPropertyIndexEntry_t) * i))), sizeof(aafPropertyIndexEntry_t) ) && \ + (Value = propStream + valueOffset); \ + valueOffset += Entry._length, \ + i++ ) + + + @@ -701,7 +728,7 @@ typedef struct _aafData * @return A pointer to the newly allocated structure. */ -AAF_Data * aaf_alloc( struct dbg *dbg ); +AAF_Data * aaf_alloc( struct aafLog *log ); /** @@ -758,7 +785,7 @@ void aaf_release( AAF_Data **aafd ); * @return Pointer to a null-terminated string holding the Object's path. */ -wchar_t * aaf_get_ObjectPath( aafObject *Obj ); +char * aaf_get_ObjectPath( aafObject *Obj ); /** @@ -776,6 +803,16 @@ wchar_t * aaf_get_ObjectPath( aafObject *Obj ); aafObject * aaf_get_ObjectByWeakRef( aafObject *list, aafWeakRef_t *ref ); +aafUID_t * aaf_get_InterpolationIdentificationByWeakRef( AAF_Data *aafd, aafWeakRef_t *InterpolationDefWeakRef ); +aafUID_t * aaf_get_OperationIdentificationByWeakRef( AAF_Data *aafd, aafWeakRef_t *OperationDefWeakRef ); +aafUID_t * aaf_get_ContainerIdentificationByWeakRef( AAF_Data *aafd, aafWeakRef_t *ContainerDefWeakRef ); +aafUID_t * aaf_get_DataIdentificationByWeakRef( AAF_Data *aafd, aafWeakRef_t *DataDefWeakRef ); + + +aafObject * aaf_get_ObjectAncestor( aafObject *Obj, const aafUID_t *ClassID ); + +int aaf_ObjectInheritsClass( aafObject *Obj, const aafUID_t *classID ); + /** * Retrieves a Mob Object by its given MobID. @@ -796,6 +833,9 @@ aafObject * aaf_get_MobSlotBySlotID( aafObject *MobSlots, aafSlotID_t SlotID ); + +aafObject * aaf_get_EssenceDataByMobID( AAF_Data *aafd, aafMobID_t *MobID ); + /** * Loops through each aafObject of a list, that is of a Set or Vector. It is also * possible to filter the returned Object by ClassID. @@ -821,10 +861,14 @@ int _aaf_foreach_ObjectInSet( aafObject **Obj, * be used istead of directly calling _aaf_foreach_ObjectInSet(). */ -#define aaf_foreach_ObjectInSet( Obj, head, filter ) \ +#define AAF_foreach_ObjectInSet( Obj, head, filter ) \ while ( _aaf_foreach_ObjectInSet( Obj, head, filter ) ) + + +void * aaf_get_TaggedValueByName( AAF_Data *aafd, aafObject *TaggedValueVector, const char *name, const aafUID_t *type ); + /** * Retrieves an Object property by ID. * @@ -839,6 +883,9 @@ aafProperty * aaf_get_property( aafObject *Obj, aafPID_t pid ); +aafUID_t * aaf_get_ParamDefIDByName( AAF_Data *aafd, const char *name ); + + /** * Retrieves a Property ID by its name. * @@ -849,9 +896,10 @@ aafProperty * aaf_get_property( aafObject *Obj, * 0 otherwise. */ -aafPID_t aaf_get_PropertyIDByName( AAF_Data *aafd, - const wchar_t *name ); +aafPID_t aaf_get_PropertyIDByName( AAF_Data *aafd, + const char *name ); +aafUID_t * aaf_get_OperationDefIDByName( AAF_Data *aafd, const char *OpDefName ); /** @@ -881,7 +929,7 @@ void * aaf_get_propertyValue( aafObject *Obj, /** * Safely get an Indirect value, after it was retrieved using aaf_get_propertyValue(). * Function checks value type and in case of AAFTypeID_String, performs allocation - * and conversion to system wchar_t*. + * and UTF8 conversion. * * Caller must free the returned value, only if Indirect is of type * AAFTypeID_String. @@ -890,7 +938,7 @@ void * aaf_get_propertyValue( aafObject *Obj, * @param Indirect Pointer to the Indirect structure. * @param typeDef Type definition expected from the Indirect. * - * @return A pointer to the Indirect value, or a pointer to an allocated wchar_t if Indirect is AAFTypeID_String\n + * @return A pointer to the Indirect value, or a pointer to an allocated char if Indirect is AAFTypeID_String\n * NULL in case of error. */ diff --git a/include/libaaf/AAFDump.h b/include/libaaf/AAFDump.h index 091081e..d921f62 100644 --- a/include/libaaf/AAFDump.h +++ b/include/libaaf/AAFDump.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -26,22 +26,22 @@ #include +void aaf_dump_Header( AAF_Data *aafd, const char *padding ); -void aaf_dump_Header( AAF_Data *aafd ); +void aaf_dump_Identification( AAF_Data *aafd, const char *padding ); -void aaf_dump_Identification( AAF_Data *aafd ); +void aaf_dump_rawProperties( AAF_Data *aafd, aafByte_t *propStream, const char *padding ); -void aaf_dump_rawProperties( AAF_Data *aafd, aafByte_t *propStream ); +void aaf_dump_ObjectProperty( AAF_Data *aafd, aafProperty *Prop, const char *padding ); -void aaf_dump_ObjectProperty( AAF_Data *aafd, aafProperty *Prop ); +void aaf_dump_ObjectProperties( AAF_Data *aafd, aafObject *Obj, const char *padding ); -void aaf_dump_ObjectProperties( AAF_Data *aafd, aafObject *Obj ); +void aaf_dump_TaggedValueSet( AAF_Data *aafd, aafObject *ObjCollection, const char *padding ); -void aaf_dump_nodeStreamProperties( AAF_Data *aafd, cfbNode *node ); +void aaf_dump_nodeStreamProperties( AAF_Data *aafd, cfbNode *node, const char *padding ); -void aaf_dump_MetaDictionary( AAF_Data *aafd ); - -void aaf_dump_Classes( AAF_Data *aafd ); +void aaf_dump_MetaDictionary( AAF_Data *aafd, const char *padding ); +void aaf_dump_Classes( AAF_Data *aafd, const char *padding ); #endif // ! __AAFDump_h__ diff --git a/include/libaaf/AAFIAudioFiles.h b/include/libaaf/AAFIAudioFiles.h deleted file mode 100644 index 8012246..0000000 --- a/include/libaaf/AAFIAudioFiles.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2017-2023 Adrien Gesta-Fline - * - * This file is part of libAAF. - * - * 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 __AAFIAudioFiles_h__ -#define __AAFIAudioFiles_h__ - -#include - -#include - -wchar_t * aafi_locate_external_essence_file( AAF_Iface *aafi, const wchar_t *original_file_path, const char *search_location ); - -int aafi_extract_audio_essence( AAF_Iface *aafi, aafiAudioEssence *audioEssence, const char *outfilepath, const wchar_t *forcedFileName ); - -int aafi_parse_audio_essence( AAF_Iface *aafi, aafiAudioEssence *audioEssence ); - - -#endif // !__AAFIAudioFiles_h__ diff --git a/include/libaaf/AAFIEssenceFile.h b/include/libaaf/AAFIEssenceFile.h new file mode 100644 index 0000000..c774b94 --- /dev/null +++ b/include/libaaf/AAFIEssenceFile.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017-2024 Adrien Gesta-Fline + * + * This file is part of libAAF. + * + * 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 __AAFIEssenceFile_h__ +#define __AAFIEssenceFile_h__ + +/** + * @file LibAAF/AAFIface/AAFIEssenceFile.h + * @brief AAF processing + * @author Adrien Gesta-Fline + * @version 0.1 + * @date 27 june 2024 + * + * @ingroup AAFIface + * @addtogroup AAFIface + * @{ + */ + +#include + + + +char * aafi_locate_external_essence_file( AAF_Iface *aafi, const char *original_uri_filepath, const char *search_location ); + +/** + * Extract audio essence file. + * + * @param aafi XXXXXX + */ +int aafi_extractAudioEssenceFile( AAF_Iface *aafi, aafiAudioEssenceFile *audioEssenceFile, enum aafiExtractFormat extractFormat, const char *outfilepath, uint64_t sampleOffset, uint64_t sampleLength, const char *forcedFileName, char **usable_file_path ); + +int aafi_extractAudioClip( AAF_Iface *aafi, aafiAudioClip *audioClip, enum aafiExtractFormat extractFormat, const char *outfilepath ); + +int aafi_parse_audio_essence( AAF_Iface *aafi, aafiAudioEssenceFile *audioEssenceFile ); + +int aafi_build_unique_audio_essence_name( AAF_Iface *aafi, aafiAudioEssenceFile *audioEssenceFile ); + +/** + * @} + */ +#endif // !__AAFIEssenceFile_h__ diff --git a/include/libaaf/AAFIParser.h b/include/libaaf/AAFIParser.h index eb35c9c..18acba1 100644 --- a/include/libaaf/AAFIParser.h +++ b/include/libaaf/AAFIParser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -54,8 +54,6 @@ typedef struct trace_dump { int lv; // current level int *ll; // level loop : each entry correspond to a level and tell if there is more to print int eob; // end of branch - int hc; // have children - int sub; } td; @@ -66,47 +64,44 @@ typedef struct trace_dump { __td.lv = __ptd->lv+offset; \ __td.ll = __ptd->ll; \ __td.ll[__td.lv] = (offset > 0) ? 0 : __td.ll[__td.lv]; \ - __td.eob = 0; \ - __td.hc = 0; \ - __td.sub = 0; \ + __td.eob = (offset) ? 0 : __ptd->eob; \ -#define DUMP_OBJ( aafi, Obj, __td ) \ - aafi_dump_obj( aafi, Obj, __td, TD_OK, __LINE__, "" ); +#define TRACE_OBJ( aafi, Obj, __td ) \ + aafi_dump_obj( aafi, Obj, __td, TD_OK, __func__, __LINE__, "" ); -#define DUMP_OBJ_INFO( aafi, Obj, __td, ... ) \ - aafi_dump_obj( aafi, Obj, __td, TD_OK, __LINE__, __VA_ARGS__ ); +#define TRACE_OBJ_INFO( aafi, Obj, __td, ... ) \ + aafi_dump_obj( aafi, Obj, __td, TD_INFO, __func__, __LINE__, __VA_ARGS__ ); -#define DUMP_OBJ_WARNING( aafi, Obj, __td, ... ) \ - aafi_dump_obj( aafi, Obj, __td, TD_WARNING, __LINE__, __VA_ARGS__ ); +#define TRACE_OBJ_WARNING( aafi, Obj, __td, ... ) \ + aafi_dump_obj( aafi, Obj, __td, TD_WARNING, __func__, __LINE__, __VA_ARGS__ ); -#define DUMP_OBJ_ERROR( aafi, Obj, __td, ... ) \ +#define TRACE_OBJ_ERROR( aafi, Obj, __td, ... ) \ (__td)->eob = 1; \ - aafi_dump_obj( aafi, Obj, __td, TD_ERROR, __LINE__, __VA_ARGS__ ); + aafi_dump_obj( aafi, Obj, __td, TD_ERROR, __func__, __LINE__, __VA_ARGS__ ); -#define DUMP_OBJ_NO_SUPPORT( aafi, Obj, __td ) \ - (__td)->eob = 1; \ - aafi_dump_obj_no_support( aafi, Obj, __td, __LINE__ ); +#define TRACE_OBJ_NO_SUPPORT( aafi, Obj, __td ) \ + aafi_dump_obj( aafi, Obj, __td, TD_NOT_SUPPORTED, __func__, __LINE__, "" ); +#define AAFI_foreach_ObjectInSet( Obj, head, i, __td ) \ + i = 0;\ + while ( _aaf_foreach_ObjectInSet( Obj, head, NULL ) && \ + (__td.ll[__td.lv] = (head->Header->_entryCount > 1) ? (int)(head->Header->_entryCount - i++) : 0) >= 0 ) int aafi_retrieveData( AAF_Iface *aafi ); + /* * The following functions are declared beyond AAFIparser.c scope, * so they are accessible to vendor-specific files (Resolve.c, ProTools.c, etc.) */ -void aafi_dump_obj( AAF_Iface *aafi, aafObject *Obj, struct trace_dump *__td, int state, int line, const char *fmt, ... ); - -void aafi_dump_obj_no_support( AAF_Iface *aafi, aafObject *Obj, struct trace_dump *__td, int line ); +void aafi_dump_obj( AAF_Iface *aafi, aafObject *Obj, struct trace_dump *__td, int state, const char *func, int line, const char *fmt, ... ); void aafi_trace_obj( AAF_Iface *aafi, aafObject *Obj, const char *color ); -int aafi_parse_Segment( AAF_Iface *aafi, aafObject *Segment, td *__ptd ); - - #endif // !__AAFIParser_h__ diff --git a/include/libaaf/AAFIface.h b/include/libaaf/AAFIface.h index c7cce35..90adff3 100644 --- a/include/libaaf/AAFIface.h +++ b/include/libaaf/AAFIface.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -45,10 +45,16 @@ enum aafiEssenceType { AAFI_ESSENCE_TYPE_WAVE = 0x02, AAFI_ESSENCE_TYPE_AIFC = 0x03, AAFI_ESSENCE_TYPE_BWAV = 0x04, - AAFI_ESSENCE_TYPE_UNK = 0xff, /* non-pcm */ + AAFI_ESSENCE_TYPE_UNK = 0xff /* non-pcm */ }; +enum aafiExtractFormat { + AAFI_EXTRACT_DEFAULT = 0, + AAFI_EXTRACT_WAV, + AAFI_EXTRACT_BWAV +}; + /** * Flags for aafiAudioGain.flags. @@ -56,8 +62,8 @@ enum aafiEssenceType { typedef enum aafiAudioGain_e { - AAFI_AUDIO_GAIN_CONSTANT = 1<<0, //0x0001 - AAFI_AUDIO_GAIN_VARIABLE = 1<<1, //0x0002 + AAFI_AUDIO_GAIN_CONSTANT = 1<<0, + AAFI_AUDIO_GAIN_VARIABLE = 1<<1, } aafiAudioGain_e; @@ -74,12 +80,12 @@ typedef enum aafiAudioGain_e typedef enum aafiTransition_e { - AAFI_TRANS_SINGLE_CURVE = 1<<4, //0x0010 - AAFI_TRANS_TWO_CURVE = 1<<5, //0x0020 + AAFI_TRANS_SINGLE_CURVE = 1<<4, + AAFI_TRANS_TWO_CURVE = 1<<5, - AAFI_TRANS_FADE_IN = 1<<6, //0x0040 - AAFI_TRANS_FADE_OUT = 1<<7, //0x0080 - AAFI_TRANS_XFADE = 1<<8, //0x0100 + AAFI_TRANS_FADE_IN = 1<<6, + AAFI_TRANS_FADE_OUT = 1<<7, + AAFI_TRANS_XFADE = 1<<8, } aafiTransition_e; @@ -102,16 +108,16 @@ typedef enum aafiTransition_e typedef enum aafiInterpolation_e { - AAFI_INTERPOL_NONE = 1<<10, //0x0400 - AAFI_INTERPOL_LINEAR = 1<<11, //0x0800 - AAFI_INTERPOL_LOG = 1<<12, //0x1000 - AAFI_INTERPOL_CONSTANT = 1<<13, //0x2000 - AAFI_INTERPOL_POWER = 1<<14, //0x4000 - AAFI_INTERPOL_BSPLINE = 1<<15, //0x8000 + AAFI_INTERPOL_NONE = 1<<10, + AAFI_INTERPOL_LINEAR = 1<<11, + AAFI_INTERPOL_LOG = 1<<12, + AAFI_INTERPOL_CONSTANT = 1<<13, + AAFI_INTERPOL_POWER = 1<<14, + AAFI_INTERPOL_BSPLINE = 1<<15, } aafiInterpolation_e; -#define AAFI_INTERPOL_MASK ( \ +#define AAFI_INTERPOL_MASK (unsigned)( \ AAFI_INTERPOL_NONE \ | AAFI_INTERPOL_LINEAR \ | AAFI_INTERPOL_LOG \ @@ -140,12 +146,14 @@ typedef enum aafiInterpolation_e typedef struct aafiTransition { + struct aafiTimelineItem *timelineItem; + /** * Should hold the transition type (either single param or two param), * the transition fade type (in, out, x) and the interpolation used. */ - int flags; + uint32_t flags; /** @@ -248,9 +256,9 @@ typedef struct aafiAudioGain * the interpolation used to calculate the values between two time points. */ - uint16_t flags; // Type : Constant (single multiplier for entire clip) or - // Variable (automation) - // Interpolation : Linear, Log, Constant, Power, BSpline + uint32_t flags; // Type : Constant (single multiplier for entire clip) or + // Variable (automation) + // Interpolation : Linear, Log, Constant, Power, BSpline /** @@ -258,7 +266,7 @@ typedef struct aafiAudioGain * gain automation, and is consequently the size of time[] and value[] arrays. */ - int64_t pts_cnt; + unsigned int pts_cnt; /** @@ -282,71 +290,141 @@ typedef struct aafiAudioGain typedef struct aafiAudioGain aafiAudioPan; +typedef struct aafiMetaData +{ + char *name; + + char *text; + + struct aafiMetaData *next; -typedef struct aafiAudioEssence +} aafiMetaData; + + +/** + * Describe a single audio essence file. + */ +typedef struct aafiAudioEssenceFile { + /** + * Holds the name of essence file, as specified in MasterMob::Name. + * This is usually the name exposed in the original software. + * This name *might* not be unique accross all essences. For a + * unique name, use #aafiAudioEssenceFile.unique_name instead. + */ - wchar_t *original_file_path; // NetworkLocator::URLString the original external essence URI holded in AAF - wchar_t *usable_file_path; // Holds a real usable file path, once an embedded essence has been extracted, or once en external essence has been found. - wchar_t *file_name; // MasterMob::Name the original file name. Might be NULL if MasterMob has no name. One should always use unique_file_name which is guaranted to be set. - wchar_t *unique_file_name; // unique name generated from file_name. Sometimes, multiple files share the same names so this unique name should be used on export. + char *name; - uint16_t clip_count; // number of clips using this essence + /** + * This is the same as #aafiAudioEssenceFile.name, but this one is guaranted to + * be unique. If an AAF has different essence files sharing the same name, + * then libaaf will add a suffix to unique_name. Thus, unique_name can be used + * instead of name when exporting embedded essences. + */ - /* - * total samples for 1 channel (no matter channel count). - * Might be retrieved from FileDescriptor::Length property, - * or from WAV/AIFF summary or file : - * (data chunk size / channels / samplesize / 8) + char *unique_name; // TODO: see creative_post.aaf + + /** + * Holds the URI path to the essence file, as specified in NetworkLocator::URLString. + * This path is *not* uri-decoded. */ - uint64_t length; - cfbNode *node; // The node holding the audio stream if embedded + char *original_file_path; + /** + * Holds a usable filepath to the essence file. It is set, either when an + * embedded essence has been extracted using aafi_extractAudioEssenceFile() or + * when an external essence file has been successfully located by libaaf. + */ + + char *usable_file_path; + + /** + * Total sample count for 1 audio channel (no matter channel count). + * + * Might be retrieved from FileDescriptor::Length property, or from WAV/AIFF + * summary or file : `data chunk size / channels / samplesize / 8` + * + * `duration = length / samplerate` + */ + + aafPosition_t length; + + /** + * Data stream CFB node, containing essence data if it's embedded. + */ + + cfbNode *node; + + /** + * Flag to tell if essence data is embedded or external. It is set only if + * FileSourceMob contains EssenceData. + */ + + uint8_t is_embedded; + + aafObject *SourceMob; aafMobID_t *sourceMobID; // Holds the SourceMob Mob::ID references this EssenceData uint32_t sourceMobSlotID; // SlotID of the MobSlot inside MasterMob (CompoMob's Sequence SourceClip::SourceMobSlotID) + aafRational_t *sourceMobSlotEditRate; + aafPosition_t sourceMobSlotOrigin; // SourceMob TimelineMobSlot::Origin + aafMobID_t *masterMobID; // Holds the MasterMob Mob::ID (used by CompoMob's Sequence SourceClip::SourceID) uint32_t masterMobSlotID; // SlotID of the MobSlot inside MasterMob (CompoMob's Sequence SourceClip::SourceMobSlotID) - aafObject *SourceMob; - enum aafiEssenceType type; // depends on PCMDescriptor WAVEDescriptor AIFCDescriptor - /* - * is only set if FileSourceMob contains EssenceData - */ - uint8_t is_embedded; + aafProperty *summary; // WAVEDescriptor AIFCDescriptor + uint64_t pcm_audio_start_offset; - // uint32_t format; uint32_t samplerate; aafRational_t *samplerateRational; // eg. { 48000, 1 } - int16_t samplesize; - int16_t channels; + uint16_t samplesize; + + /** + * Audio essence file channel count. Might be different of #aafiAudioClip.channels + */ + uint16_t channels; - aafRational_t *mobSlotEditRate; // BWF BEXT chunk data char description[256]; char originator[32]; // could be set with header::ProductName char originatorReference[32]; - uint64_t timeReference; // SourceMob TimelineMobSlot::Origin + aafPosition_t timeReference; // SourceMob TimelineMobSlot::Origin unsigned char umid[64]; // SourceMob::MobID (32 Bytes, basic form) char originationDate[10+1]; // SourceMob::CreationDate char originationTime[8+1]; // SourceMob::CreationTime + + /** + * Metadata retrieved from main MasterMob::UserComments + */ + aafiMetaData *metadata; + void *user; - // TODO peakEnveloppe - struct aafiAudioEssence *next; // aafi->Audio->essences -} aafiAudioEssence; + + + /** + * Pointer to the next essence in global essence list #aafiAudio.essenceFiles + */ + + struct aafiAudioEssenceFile *next; + +} aafiAudioEssenceFile; +/** + * aafiAudioEssencePointer is used by aafiAudioClip, to points to one or more + * aafiAudioEssenceFile and specify which channel of essence file the clip uses. + */ typedef struct aafiAudioEssencePointer { - aafiAudioEssence *essence; // single essence, not list ! - int essenceChannel; // channel selector inside multichannel essence. If zero, then all essence channels must be used. + aafiAudioEssenceFile *essenceFile; + uint32_t essenceChannel; // channel selector inside multichannel essence. If zero, then all essence channels must be used. void *user; @@ -362,12 +440,12 @@ typedef struct aafiAudioEssencePointer typedef struct aafiVideoEssence { - wchar_t *original_file_path; // NetworkLocator::URLString should point to original essence file if external (and in some cases, points to the AAF itself if internal..) - wchar_t *usable_file_path; // TODO, not that used.. to be tweaked. ---- Holds the file path, once the essence has been exported, copied or linked. - wchar_t *file_name; // MasterMob::Name -> file name - wchar_t *unique_file_name; // unique name generated from file_name. Sometimes, multiple files share the same names so this unique name should be used on export. + char *original_file_path; // NetworkLocator::URLString should point to original essence file if external (and in some cases, points to the AAF itself if internal..) + char *usable_file_path; // TODO, not that used.. to be tweaked. ---- Holds the file path, once the essence has been exported, copied or linked. + char *name; // MasterMob::Name -> file name + char *unique_name; // unique name generated from aafiVideoEssence->name. Sometimes, multiple files share the same names so this unique name should be used on export. - uint64_t length; // Length of Essence Data + aafPosition_t length; // Length of Essence Data cfbNode *node; // The node holding the audio stream if embedded @@ -386,6 +464,11 @@ typedef struct aafiVideoEssence aafProperty *summary; + /** + * Metadata retrieved from main MasterMob::UserComments + */ + aafiMetaData *metadata; + // TODO peakEnveloppe struct aafiVideoEssence *next; @@ -399,11 +482,33 @@ struct aafiVideoTrack; typedef struct aafiAudioClip { - + /** + * The track that audio clip is attached to. + */ struct aafiAudioTrack *track; - int channels; // channel count of clip (might be different of essence->channels) + /** + * Audio channel count of audio clip. Might be different of #aafiAudioEssenceFile.channels + */ + int channels; + + /** + * List of essence pointer that compose an audio clip. + * + * An audio clip can hold a single aafiAudioEssencePointer, if clip is mono or + * Each aafiAudioEssencePointer points to a single aafiAudioEssenceFile. + * + * If clip is mono, it has a single aafiAudioEssencePointer which points to a + * single aafiAudioEssenceFile. + */ aafiAudioEssencePointer *essencePointerList; + + /** + * SubCLip name is set in rare cases, when a SourceClip targets a SubClip + * CompositionMob with a name (see AAFUsage_SubClip) + */ + char *subClipName; + /* * Some editors (like Resolve) support automation attached to a clip AND a fixed value clip gain */ @@ -412,9 +517,6 @@ typedef struct aafiAudioClip int mute; - int channel_count; - - aafPosition_t pos; /* in edit unit, edit rate definition is aafiAudioTrack->edit_rate */ aafPosition_t len; /* in edit unit, edit rate definition is aafiAudioTrack->edit_rate */ @@ -441,7 +543,10 @@ typedef struct aafiAudioClip */ aafPosition_t essence_offset; - struct aafiTimelineItem *Item; // Corresponding timeline item, currently used in ardour to retrieve fades/x-fades + aafiMetaData *metadata; + + + struct aafiTimelineItem *timelineItem; // Corresponding timeline item } aafiAudioClip; @@ -461,6 +566,8 @@ typedef struct aafiVideoClip aafMobID_t *masterMobID; // MobID of the associated MasterMob (PID_SourceReference_SourceID) + struct aafiTimelineItem *timelineItem; // Corresponding timeline item + } aafiVideoClip; @@ -481,13 +588,30 @@ typedef enum aafiTimelineItem_type_e typedef struct aafiTimelineItem { - int type; + /** + * Identifies timelineItem type. + */ + aafiTimelineItem_type_e type; + + /** + * Item position on the timeline. Value is in edit unit, specified by #aafiAudioTrack.edit_rate. + */ + aafPosition_t pos; + + /** + * Item length on the timeline. Value is in edit unit, specified by #aafiAudioTrack.edit_rate. + */ + aafPosition_t len; + + /** + * The actual timelineItem object data. Can hold an aafiTransition, aafiAudioClip + * or aafiVideoClip structure, depending on #aafiTimelineItem.type value. + */ + void *data; struct aafiTimelineItem *next; struct aafiTimelineItem *prev; - void *data; /* aafiTransition or aafiAudioClip or aafiVideoClip */ - } aafiTimelineItem; @@ -555,8 +679,6 @@ typedef struct aafiAudioTrack { /** * Track number - * TODO Should it start at one ? - * TODO Optional, should have a guess (i++) option. */ uint32_t number; @@ -568,7 +690,7 @@ typedef struct aafiAudioTrack * Track name */ - wchar_t *name; + char *name; /** @@ -580,13 +702,17 @@ typedef struct aafiAudioTrack aafiAudioPan *pan; + char solo; + char mute; + /** * Holds the timeline items of that track, that is aafiAudioClip and aafiTransition * structures. */ - struct aafiTimelineItem *Items; + struct aafiTimelineItem *timelineItems; + int clipCount; /** @@ -631,7 +757,7 @@ typedef struct aafiVideoTrack * Track name */ - wchar_t *name; + char *name; /** @@ -639,7 +765,7 @@ typedef struct aafiVideoTrack * structures. */ - struct aafiTimelineItem *Items; + struct aafiTimelineItem *timelineItems; /** @@ -670,17 +796,6 @@ typedef struct aafiVideoTrack -typedef struct aafiUserComment -{ - wchar_t *name; - - wchar_t *text; - - struct aafiUserComment *next; - -} aafiUserComment; - - typedef struct aafiAudio { @@ -688,25 +803,26 @@ typedef struct aafiAudio * Holds the sequence start timecode. */ - aafPosition_t start; + aafPosition_t start; - int16_t samplesize; - int64_t samplerate; - aafRational_t *samplerateRational; // eg. { 48000, 1 } + uint16_t samplesize; + uint32_t samplerate; + aafRational_t *samplerateRational; // eg. { 48000, 1 } /** * Holds the Essence list. */ - aafiAudioEssence *Essences; + int essenceCount; + aafiAudioEssenceFile *essenceFiles; aafiAudioEssencePointer *essencePointerList; /** * Holds the Track list. */ - aafiAudioTrack *Tracks; - uint32_t track_count; + aafiAudioTrack *Tracks; + uint32_t track_count; } aafiAudio; @@ -725,7 +841,7 @@ typedef struct aafiVideo * Holds the Essence list. */ - aafiVideoEssence *Essences; + aafiVideoEssence *essenceFiles; /** * Holds the Track list. @@ -747,8 +863,8 @@ typedef struct aafiMarker { aafPosition_t length; aafRational_t *edit_rate; - wchar_t *name; - wchar_t *comment; + char *name; + char *comment; uint16_t RGBColor[3]; struct aafiMarker *prev; @@ -758,19 +874,8 @@ typedef struct aafiMarker { -// typedef enum aafiCurrentTreeType_e -// { -// AAFI_TREE_TYPE_AUDIO = 0, -// AAFI_TREE_TYPE_VIDEO = 1 -// -// } aafiCurrentTreeType_e; - typedef struct aafiContext { - - /* Set in parse_MobSlot(), specifies if we're inside an audio or video context */ - // aafiCurrentTreeType_e current_tree_type; - /* * Current MobSlot Segment's DataDefinition * Mob::Slots > MobSlot::Segment > Component::DataDefinition @@ -781,11 +886,10 @@ typedef struct aafiContext /* Clip */ + aafObject *TopLevelCompositionMob; aafiAudioTrack *current_track; - /* Must be casted to aafiAudioTrack or aafiVideoTrack, according to aafiContext::current_tree_type */ - // void * current_track; // int current_track_number; // used only when missing MobSlot::PhysicalTrackNumber // aafPosition_t current_pos; @@ -794,46 +898,49 @@ typedef struct aafiContext int current_clip_is_muted; int current_clip_is_combined; // Inside OperationGroup::AAFOperationDef_AudioChannelCombiner - int current_combined_clip_total_channel; + uint32_t current_combined_clip_total_channel; int current_combined_clip_channel_num; // current SourceClip represents channel num aafPosition_t current_combined_clip_forced_length; /* Transition */ aafiTransition *current_transition; + char *subClipName; + int current_opgroup_affect_track; /* Gain */ aafiAudioGain *current_clip_gain; - aafiAudioGain *current_clip_automation; - int clips_using_gain; // if none then free( current_clip_gain ); - int clips_using_automation; + int current_clip_gain_is_used; // if not then free( current_clip_gain ); + aafiAudioGain *current_clip_variable_gain; + int current_clip_variable_gain_is_used; /* Essence */ - // aafiAudioEssence *current_audioEssence; - // void *current_essence; - aafiAudioEssence *current_essence; + aafiAudioEssenceFile *current_audio_essence; aafiVideoEssence *current_video_essence; aafRational_t *current_markers_edit_rate; - int is_inside_derivation_chain; + aafRational_t *avid_warp_clip_edit_rate; + struct options { int trace; - int trace_meta; - wchar_t *dump_class_aaf_properties; - wchar_t *dump_class_raw_properties; + int dump_meta; + int dump_tagged_value; + char *dump_class_aaf_properties; + char *dump_class_raw_properties; char *media_location; - char forbid_nonlatin_filenames; + // int forbid_nonlatin_filenames; + int mobid_essence_filename; + /* vendor specific */ - uint32_t resolve; - uint32_t protools; + int protools; } options; } aafiContext; @@ -862,7 +969,7 @@ typedef struct AAF_Iface aafiMarker *Markers; - wchar_t *compositionName; + char *compositionName; aafPosition_t compositionStart; // sets from aafi->Timecode->start aafRational_t *compositionStart_editRate; @@ -871,10 +978,13 @@ typedef struct AAF_Iface aafRational_t *compositionLength_editRate; /* might be NULL if file empty ! */ - aafiUserComment *Comments; + /** + * Metadata retrieved from main CompositionMob::UserComments + */ + aafiMetaData *metadata; - struct dbg *dbg; + struct aafLog *log; } AAF_Iface; @@ -882,113 +992,215 @@ typedef struct AAF_Iface +/** + * @name Function macros + * @{ + */ +/** + * Loops through each audio track in AAF file. + * + * @param aafi Pointer to the current AAF_Iface struct. + * @param audioTrack NULL pointer to an aafiAudioTrack struct. + */ +#define AAFI_foreachAudioTrack( aafi, audioTrack ) \ + for ( audioTrack = aafi->Audio->Tracks; \ + audioTrack != NULL; \ + audioTrack = audioTrack->next ) \ -#define foreach_audioTrack( audioTrack, aafi ) \ - for ( audioTrack = aafi->Audio->Tracks; \ - audioTrack != NULL; \ - audioTrack = audioTrack->next ) \ - - +/** + * Loops through each video track in AAF file. + * + * @param aafi Pointer to the current AAF_Iface struct. + * @param videoTrack NULL pointer to an aafiVideoTrack struct. + */ +#define AAFI_foreachVideoTrack( aafi, videoTrack ) \ + for ( videoTrack = aafi->Video->Tracks; \ + videoTrack != NULL; \ + videoTrack = videoTrack->next ) \ -#define foreach_videoTrack( videoTrack, aafi ) \ - for ( videoTrack = aafi->Video->Tracks; \ - videoTrack != NULL; \ - videoTrack = videoTrack->next ) \ +/** + * Loops through each timelineItem of a track. Audio tracks can contain + * either clips (AAFI_AUDIO_CLIP) or crossfades (AAFI_TRANS). + * + * @param track Pointer to an aafiAudioTrack struct. + * @param timelineItem NULL pointer to an aafiTimelineItem struct. + */ +#define AAFI_foreachTrackItem( track, timelineItem ) \ + for ( timelineItem = track->timelineItems; \ + timelineItem != NULL; \ + timelineItem = timelineItem->next ) \ +/** + * Loops through each audio essence pointer in AAF file. + * + * @param aafi Pointer to the current AAF_Iface struct. + * @param audioEssencePointer NULL pointer to an aafiAudioEssencePointer struct. + */ +#define AAFI_foreachAudioEssencePointer( aafi, audioEssencePointer ) \ + for ( audioEssencePointer = aafi->Audio->essencePointerList; \ + audioEssencePointer != NULL; \ + audioEssencePointer = audioEssencePointer->aafiNext ) \ -#define foreach_Item( item, track ) \ - for ( item = track->Items; \ - item != NULL; \ - item = item->next ) \ +/** + * Loops through each audio essence file in AAF file. + * + * @param aafi Pointer to the current AAF_Iface struct. + * @param audioEssenceFile NULL pointer to an aafiAudioEssenceFile struct. + */ +#define AAFI_foreachAudioEssenceFile( aafi, audioEssenceFile ) \ + for ( audioEssenceFile = aafi->Audio->essenceFiles; \ + audioEssenceFile != NULL; \ + audioEssenceFile = audioEssenceFile->next ) \ +/** + * Loops through each video essence file in AAF file. + * + * @param aafi Pointer to the current AAF_Iface struct. + * @param videoEssenceFile NULL pointer to an aafiVideoEssence struct. + */ +#define AAFI_foreachVideoEssence( aafi, videoEssenceFile ) \ + for ( videoEssenceFile = aafi->Video->essenceFiles; \ + videoEssenceFile != NULL; \ + videoEssenceFile = videoEssenceFile->next ) \ -#define AAFI_foreachAudioEssencePointerInFile( essencePointer, aafi ) \ - for ( essencePointer = aafi->Audio->essencePointerList; essencePointer != NULL; essencePointer = essencePointer->aafiNext ) +/** + * Loops through each essence pointer in a list (usualy aafiAudioClip->essencePointerList). + * + * @param essencePointerList Pointer to any aafiAudioEssencePointer struct list. + * @param essencePointer NULL pointer to an aafiAudioEssencePointer struct. + */ +#define AAFI_foreachEssencePointer( essencePointerList, essencePointer ) \ + for ( essencePointer = essencePointerList; \ + essencePointer != NULL; \ + essencePointer = essencePointer->next ) \ -#define AAFI_foreachAudioEssencePointer( essencePointer, essencePtrList ) \ - for ( essencePointer = essencePtrList; essencePointer != NULL; essencePointer = essencePointer->next ) +#define AAFI_foreachEssence( essenceFileList, essenceFile ) \ + for ( essenceFile = essenceFileList; \ + essenceFile != NULL; \ + essenceFile = essenceFile->next ) \ -#define foreachEssence( essence, essenceList ) \ - for ( essence = essenceList; essence != NULL; essence = essence->next ) +/** + * Loops through each marker in AAF file. + * + * @param aafi Pointer to the current AAF_Iface struct. + * @param marker NULL pointer to an aafiMarker struct. + */ +#define AAFI_foreachMarker( aafi, marker ) \ + for ( marker = aafi->Markers; \ + marker != NULL; \ + marker = marker->next ) \ -#define foreachMarker( marker, aafi ) \ - for ( marker = aafi->Markers; marker != NULL; marker = marker->next ) +#define AAFI_foreachMetadata( metadataList, metadata ) \ + for ( metadata = metadataList; \ + metadata != NULL; \ + metadata = metadata->next ) \ +/** + * @} + */ +AAF_Iface * aafi_alloc( AAF_Data *aafd ); -void aafi_set_debug( AAF_Iface *aafi, verbosityLevel_e v, int ansicolor, FILE *fp, void (*callback)(struct dbg *dbg, void *ctxdata, int lib, int type, const char *srcfile, const char *srcfunc, int lineno, const char *msg, void *user), void *user ); +void aafi_set_debug( AAF_Iface *aafi, verbosityLevel_e v, int ansicolor, FILE *fp, void (*callback)(struct aafLog *log, void *ctxdata, int lib, int type, const char *srcfile, const char *srcfunc, int lineno, const char *msg, void *user), void *user ); int aafi_set_option_int( AAF_Iface *aafi, const char *optname, int val ); + int aafi_set_option_str( AAF_Iface *aafi, const char *optname, const char *val ); -AAF_Iface * aafi_alloc( AAF_Data *aafd ); +int aafi_load_file( AAF_Iface *aafi, const char *file ); void aafi_release( AAF_Iface **aafi ); -int aafi_load_file( AAF_Iface *aafi, const char * file ); +aafiAudioClip * aafi_timelineItemToAudioClip( aafiTimelineItem *audioItem ); -aafiTransition * aafi_get_fadein( aafiTimelineItem *audioItem ); +aafiTransition * aafi_timelineItemToCrossFade( aafiTimelineItem *audioItem ); -aafiTransition * aafi_get_fadeout( aafiTimelineItem *audioItem ); +aafiTransition * aafi_getFadeIn( aafiAudioClip *audioClip ); -aafiTransition * aafi_get_xfade( aafiTimelineItem *audioItem ); +aafiTransition * aafi_getFadeOut( aafiAudioClip *audioClip ); -aafiMarker * aafi_newMarker( AAF_Iface *aafi, aafRational_t *editRate, aafPosition_t start, aafPosition_t length, wchar_t *name, wchar_t *comment, uint16_t *RGBColor[3] ); +int aafi_get_clipIndex( aafiAudioClip *audioClip ); -void aafi_freeMarkers( aafiMarker **aafi ); -aafiAudioTrack * aafi_newAudioTrack( AAF_Iface *aafi ); +aafPosition_t aafi_convertUnit( aafPosition_t value, aafRational_t *valueEditRate, aafRational_t *destEditRate ); + +uint64_t aafi_convertUnitUint64( aafPosition_t value, aafRational_t *valueEditRate, aafRational_t *destEditRate ); + + +int aafi_removeTimelineItem( AAF_Iface *aafi, aafiTimelineItem *timelineItem ); + +int aafi_getAudioEssencePointerChannelCount( aafiAudioEssencePointer *essencePointerList ); + +int aafi_applyGainOffset( AAF_Iface *aafi, aafiAudioGain **gain, aafiAudioGain *offset ); + -void aafi_freeAudioTracks( aafiAudioTrack **tracks ); +aafiAudioTrack * aafi_newAudioTrack( AAF_Iface *aafi ); aafiVideoTrack * aafi_newVideoTrack( AAF_Iface *aafi ); -void aafi_freeVideoTracks( aafiVideoTrack **tracks ); +aafiTimelineItem * aafi_newTimelineItem( AAF_Iface *aafi, void *track, int itemType, void *data ); -aafiTimelineItem * aafi_newTimelineItem( AAF_Iface *aafi, void *track, int itemType ); +aafiAudioClip * aafi_newAudioClip( AAF_Iface *aafi, aafiAudioTrack *track ); -int aafi_removeTimelineItem( AAF_Iface *aafi, aafiTimelineItem *item ); +aafiVideoClip * aafi_newVideoClip( AAF_Iface *aafi, aafiVideoTrack *track ); -void aafi_freeAudioGain( aafiAudioGain *gain ); +aafiTransition * aafi_newTransition( AAF_Iface *aafi, aafiAudioTrack *track ); -void aafi_freeAudioPan( aafiAudioPan *pan ); -void aafi_freeAudioClip( aafiAudioClip *audioClip ); +aafiMarker * aafi_newMarker( AAF_Iface *aafi, aafRational_t *editRate, aafPosition_t start, aafPosition_t length, char *name, char *comment, uint16_t *RGBColor[] ); -void aafi_freeAudioEssencePointer( aafiAudioEssencePointer *audioEssenceGroupEntry ); +aafiMetaData * aafi_newMetadata( AAF_Iface *aafi, aafiMetaData **CommentList ); -void aafi_freeTimelineItem( aafiTimelineItem **item ); -void aafi_freeTimelineItems( aafiTimelineItem **items ); +aafiAudioEssencePointer * aafi_newAudioEssencePointer( AAF_Iface *aafi, aafiAudioEssencePointer **list, aafiAudioEssenceFile *audioEssenceFile, uint32_t *essenceChannelNum ); -aafiUserComment * aafi_newUserComment( AAF_Iface *aafi, aafiUserComment **CommentList ); +aafiAudioEssenceFile * aafi_newAudioEssence( AAF_Iface *aafi ); -void aafi_freeUserComments( aafiUserComment **CommentList ); +aafiVideoEssence * aafi_newVideoEssence( AAF_Iface *aafi ); -void aafi_freeTransition( aafiTransition *trans ); +aafiAudioGain * aafi_newAudioGain( AAF_Iface *aafi, enum aafiAudioGain_e type, enum aafiInterpolation_e interpol, aafRational_t *singleValue ); +aafiAudioGain * aafi_newAudioPan( AAF_Iface *aafi, enum aafiAudioGain_e type, enum aafiInterpolation_e interpol, aafRational_t *singleValue ); -aafiAudioEssence * aafi_newAudioEssence( AAF_Iface *aafi ); -aafiAudioEssencePointer * aafi_newAudioEssencePointer( AAF_Iface *aafi, aafiAudioEssencePointer **list, aafiAudioEssence *audioEssence, uint32_t *essenceChannelNum ); +void aafi_freeAudioTracks( aafiAudioTrack **tracks ); -void aafi_freeAudioEssences( aafiAudioEssence **essences ); +void aafi_freeVideoTracks( aafiVideoTrack **tracks ); -aafiVideoEssence * aafi_newVideoEssence( AAF_Iface *aafi ); -void aafi_freeVideoEssences( aafiVideoEssence **videoEssence ); +void aafi_freeTimelineItems( aafiTimelineItem **timelineItems ); + +void aafi_freeTimelineItem( aafiTimelineItem *timelineItem ); + +void aafi_freeAudioClip( aafiAudioClip *audioClip ); + +void aafi_freeTransition( aafiTransition *trans ); -int aafi_getAudioEssencePointerChannelCount( aafiAudioEssencePointer *essencePointerList ); +void aafi_freeMarkers( aafiMarker **aafi ); + +void aafi_freeMetadata( aafiMetaData **CommentList ); + + +void aafi_freeAudioEssencePointer( aafiAudioEssencePointer *audioEssenceGroupEntry ); + +void aafi_freeAudioEssences( aafiAudioEssenceFile **audioEssenceFiles ); + +void aafi_freeVideoEssences( aafiVideoEssence **videoEssenceFile ); + + +void aafi_freeAudioGain( aafiAudioGain *gain ); + +void aafi_freeAudioPan( aafiAudioPan *pan ); /** * @} diff --git a/include/libaaf/AAFToText.h b/include/libaaf/AAFToText.h index 4d3a8de..123569e 100644 --- a/include/libaaf/AAFToText.h +++ b/include/libaaf/AAFToText.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -21,9 +21,6 @@ #ifndef __AAFToText_h__ #define __AAFToText_h__ -#include -#include - #include #include #include @@ -34,79 +31,81 @@ cfb_CLSIDToText( (const cfbCLSID_t*)auid ) -const wchar_t * aaft_MobIDToText( aafMobID_t *mobid ); +const char * aaft_MobIDToText( aafMobID_t *mobid ); + +const char * aaft_TimestampToText( aafTimeStamp_t *ts ); -const wchar_t * aaft_TimestampToText( aafTimeStamp_t *ts ); +const char * aaft_VersionToText( aafVersionType_t *vers ); -const wchar_t * aaft_VersionToText( aafVersionType_t *vers ); +const char * aaft_ProductVersionToText( aafProductVersion_t *vers ); -const wchar_t * aaft_ProductVersionToText( aafProductVersion_t *vers ); +const char * aaft_FileKindToText( const aafUID_t *auid ); -const wchar_t * aaft_FileKindToText( const aafUID_t *auid ); +const char * aaft_TapeCaseTypeToText( aafTapeCaseType_t t ); -const wchar_t * aaft_TapeCaseTypeToText( aafTapeCaseType_t t ); +const char * aaft_VideoSignalTypeToText( aafVideoSignalType_t v ); -const wchar_t * aaft_VideoSignalTypeToText( aafVideoSignalType_t v ); +const char * aaft_TapeFormatTypeToText( aafTapeFormatType_t t ); -const wchar_t * aaft_TapeFormatTypeToText( aafTapeFormatType_t t ); +const char * aaft_FilmTypeToText( aafFilmType_t f ); -const wchar_t * aaft_FilmTypeToText( aafFilmType_t f ); +const char * aaft_SignalStandardToText( aafSignalStandard_t s ); -const wchar_t * aaft_SignalStandardToText( aafSignalStandard_t s ); +const char * aaft_FieldNumberToText( aafFieldNumber_t f ); -const wchar_t * aaft_FieldNumberToText( aafFieldNumber_t f ); +const char * aaft_AlphaTransparencyToText( aafAlphaTransparency_t a ); -const wchar_t * aaft_AlphaTransparencyToText( aafAlphaTransparency_t a ); +const char * aaft_FrameLayoutToText( aafFrameLayout_t f ); -const wchar_t * aaft_FrameLayoutToText( aafFrameLayout_t f ); +const char * aaft_ColorSitingToText( aafColorSiting_t c ); -const wchar_t * aaft_ColorSitingToText( aafColorSiting_t c ); +const char * aaft_ProductReleaseTypeToText( aafProductReleaseType_t t ); -const wchar_t * aaft_ProductReleaseTypeToText( aafProductReleaseType_t t ); +const char * aaft_FadeTypeToText( aafFadeType_t f ); -const wchar_t * aaft_FadeTypeToText( aafFadeType_t f ); +const char * aaft_BoolToText( aafBoolean_t b ); -const wchar_t * aaft_BoolToText( aafBoolean_t b ); +const char * aaft_OperationCategoryToText( const aafUID_t *auid ); -const wchar_t * aaft_OperationCategoryToText( const aafUID_t *auid ); +const char * aaft_PluginCategoryToText( const aafUID_t *auid ); -const wchar_t * aaft_PluginCategoryToText( const aafUID_t *auid ); +const char * aaft_ScanningDirectionToText( aafScanningDirection_t s ); -const wchar_t * aaft_ScanningDirectionToText( aafScanningDirection_t s ); +const char * aaft_ByteOrderToText( int16_t e ); -const wchar_t * aaft_ByteOrderToText( int16_t e ); +const char * aaft_ElectroSpatialToText( aafElectroSpatialFormulation_t e ); -const wchar_t * aaft_ElectroSpatialToText( aafElectroSpatialFormulation_t e ); +const char * aaft_TypeIDToText( const aafUID_t *auid ); -const wchar_t * aaft_TypeIDToText( const aafUID_t *auid ); +const char * aaft_StoredFormToText( enum aafStoredForm_e sf ); -const wchar_t * aaft_StoredFormToText( enum aafStoredForm_e sf ); +const char * aaft_OPDefToText( const aafUID_t *auid ); -const wchar_t * aaft_OPDefToText( const aafUID_t *auid ); +const char * aaft_DataDefToText( AAF_Data *aafd, const aafUID_t *auid ); -const wchar_t * aaft_DataDefToText( AAF_Data *aafd, const aafUID_t *auid ); +const char * aaft_OperationDefToText( AAF_Data *aafd, const aafUID_t *auid ); -const wchar_t * aaft_OperationDefToText( AAF_Data *aafd, const aafUID_t *auid ); +const char * aaft_InterpolationToText( const aafUID_t *auid ); -const wchar_t * aaft_InterpolationToText( const aafUID_t *auid ); +const char * aaft_ParameterToText( AAF_Data *aafd, const aafUID_t *auid ); -const wchar_t * aaft_ParameterToText( AAF_Data *aafd, const aafUID_t *auid ); +const char * aaft_TransferCharacteristicToText( const aafUID_t *auid ); -const wchar_t * aaft_TransferCharacteristicToText( const aafUID_t *auid ); +const char * aaft_CodingEquationsToText( const aafUID_t *auid ); -const wchar_t * aaft_CodingEquationsToText( const aafUID_t *auid ); +const char * aaft_ColorPrimariesToText( const aafUID_t *auid ); -const wchar_t * aaft_ColorPrimariesToText( const aafUID_t *auid ); +const char * aaft_UsageCodeToText( const aafUID_t *auid ); -const wchar_t * aaft_UsageCodeToText( const aafUID_t *auid ); +const char * aaft_PIDToText( AAF_Data *aafd, aafPID_t pid ); -const wchar_t * aaft_PIDToText( AAF_Data *aafd, aafPID_t pid ); +const char * aaft_ClassIDToText( AAF_Data *aafd, const aafUID_t *auid ); -const wchar_t * aaft_ClassIDToText( AAF_Data *aafd, const aafUID_t *auid ); +const char * aaft_ContainerToText( const aafUID_t *auid ); -const wchar_t * aaft_ContainerToText( const aafUID_t *auid ); +const char * aaft_IndirectValueToText( AAF_Data *aafd, aafIndirect_t *Indirect ); -const wchar_t * aaft_CompressionToText( const aafUID_t *auid ); +const char * aaft_CompressionToText( const aafUID_t *auid ); #endif // !__AAFToText_h__ diff --git a/include/libaaf/AAFTypes.h b/include/libaaf/AAFTypes.h index b515dc2..dce8ade 100644 --- a/include/libaaf/AAFTypes.h +++ b/include/libaaf/AAFTypes.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -236,7 +236,8 @@ typedef struct _aafUID_t static const aafUID_t AUID_NULL = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - +static const aafUID_t AAFUID_NULL = +{0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; typedef struct _aafMobID_t { @@ -249,6 +250,9 @@ typedef struct _aafMobID_t } aafMobID_t; // 32 bytes total +static const aafMobID_t AAFMOBID_NULL = +{ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x00, 0x00, 0x00, 0x00, {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}; + typedef struct _aafIndirect_t @@ -496,10 +500,6 @@ typedef struct _aafRGBAComponent_t -static const aafUID_t AAFUID_NULL = -{0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - - /** * This structure map the first bytes in a **properties** stream diff --git a/include/libaaf/CFBDump.h b/include/libaaf/CFBDump.h index fa39241..f823b0e 100644 --- a/include/libaaf/CFBDump.h +++ b/include/libaaf/CFBDump.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -21,30 +21,27 @@ #ifndef __CFBDump_h__ #define __CFBDump_h__ -#include -#include - #include -void cfb_dump_node( CFB_Data *cfbd, cfbNode *node, int print_stream ); +void cfb_dump_node( CFB_Data *cfbd, cfbNode *node, int print_stream, const char *padding ); -void cfb_dump_nodePath( CFB_Data *cfbd, const wchar_t *path, int print_stream ); +void cfb_dump_nodePath( CFB_Data *cfbd, const char *path, int print_stream, const char *padding ); -void cfb_dump_nodeStream( CFB_Data *cfbd, cfbNode *node ); +void cfb_dump_nodeStream( CFB_Data *cfbd, cfbNode *node, const char *padding ); -void cfb_dump_nodePathStream( CFB_Data *cfbd, const wchar_t *path ); +void cfb_dump_nodePathStream( CFB_Data *cfbd, const char *path, const char *padding ); -void cfb_dump_nodePaths( CFB_Data *cfbd, uint32_t prevPath, char *strArray[], uint32_t *str_i, cfbNode *node ); +void cfb_dump_nodePaths( CFB_Data *cfbd, uint32_t prevPath, char *strArray[], uint32_t *str_i, cfbNode *node, const char *padding, int firstIteration ); -void cfb_dump_header( CFB_Data *cfbd ); +void cfb_dump_header( CFB_Data *cfbd, const char *padding ); -void cfb_dump_FAT( CFB_Data *cfbd ); +void cfb_dump_FAT( CFB_Data *cfbd, const char *padding ); -void cfb_dump_MiniFAT( CFB_Data *cfbd ); +void cfb_dump_MiniFAT( CFB_Data *cfbd, const char *padding ); -void cfb_dump_DiFAT( CFB_Data *cfbd ); +void cfb_dump_DiFAT( CFB_Data *cfbd, const char *padding ); #endif // !__CFBDump_h__ diff --git a/include/libaaf/LibCFB.h b/include/libaaf/LibCFB.h index a77e085..08082eb 100644 --- a/include/libaaf/LibCFB.h +++ b/include/libaaf/LibCFB.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -22,18 +22,16 @@ #define __LibCFB_h__ #include -#include +#include +#include -#include +#include #if defined(__linux__) + #include #include #elif defined(__APPLE__) #include -#elif defined(_MSC_VER)// MSVC - #include // MAX_PATH - #include - #define PATH_MAX MAX_PATH // TODO: can we get rid of it ? #elif defined(_WIN32) #include // MAX_PATH #include @@ -53,9 +51,6 @@ * @{ */ -#define CFB_W16TOWCHAR_STRLEN SIZE_MAX - - /** * Class Identifier structure. @@ -236,7 +231,7 @@ typedef enum customTagSTGTY * For AAF, this node represents an aafObject. */ - STGTY_STORAGE = 1, + STGTY_STORAGE = 1, /** @@ -246,7 +241,7 @@ typedef enum customTagSTGTY * a StrongRefVector or a data stream containing some essence. */ - STGTY_STREAM = 2, + STGTY_STREAM = 2, /** @@ -264,14 +259,14 @@ typedef enum customTagSTGTY * TODO What is an IPropertyStorage object ? */ - STGTY_PROPERTY = 4, + STGTY_PROPERTY = 4, #endif /** * The node is the Root node (SID 0). */ - STGTY_ROOT = 5 + STGTY_ROOT = 5 } cfbStorageType_e; @@ -284,8 +279,8 @@ typedef enum customTagSTGTY */ typedef enum tagDECOLOR { - CFB_RED = 0, - CFB_BLACK = 1 + CFB_RED = 0, + CFB_BLACK = 1 } cfbColor_e; @@ -515,9 +510,6 @@ typedef struct StructuredStorageDirectoryEntry * * A 64-byte array, for a maximum of 32 Unicode characters including a terminating * Unicode NULL character. The string shall be padded with zeros to fill the array. - * - * Should be wchar_t, but on linux wchar_t is 32 bits wide as opposed to windows - * (and thus CFB) defining wchar_t to 16 bits. Conversion is done by cfb_w16towchar() */ uint16_t _ab[CFB_NODE_NAME_SZ]; @@ -648,7 +640,7 @@ typedef struct CFB_Data * CFB file path. */ - char file[PATH_MAX + 1]; + char *file; /** @@ -728,7 +720,7 @@ typedef struct CFB_Data cfbNode *nodes; - struct dbg *dbg; + struct aafLog *log; } CFB_Data; @@ -752,7 +744,7 @@ typedef struct CFB_Data * @param id Index of the first sector in the Chain. */ -#define cfb_foreachSectorInChain( cfbd, buf, id ) \ +#define CFB_foreachSectorInChain( cfbd, buf, id ) \ for ( buf = cfb_getSector( cfbd, id ); \ id < CFB_MAX_REG_SECT && \ buf != NULL; \ @@ -771,7 +763,7 @@ typedef struct CFB_Data * @param id Index of the first mini-sector in the Chain. */ -#define cfb_foreachMiniSectorInChain( cfbd, buf, id ) \ +#define CFB_foreachMiniSectorInChain( cfbd, buf, id ) \ for ( buf = cfb_getMiniSector( cfbd, id ); \ id < CFB_MAX_REG_SECT; \ id = cfbd->miniFat[id], \ @@ -791,7 +783,7 @@ typedef struct CFB_Data * sector data. */ -#define cfb_foreachSectorInDiFATChain( cfbd, buf, id ) \ +#define CFB_foreachSectorInDiFATChain( cfbd, buf, id ) \ for ( id = cfbd->hdr->_sectDifStart, \ buf = cfb_getSector( cfbd, id ); \ id < CFB_MAX_REG_SECT; \ @@ -809,7 +801,7 @@ typedef struct CFB_Data * @param id Index of each FAT sector. */ -#define cfb_foreachFATSectorIDInDiFAT( cfbd, id ) \ +#define CFB_foreachFATSectorIDInDiFAT( cfbd, id ) \ for ( id = 0; \ id < cfbd->DiFAT_sz && \ id < cfbd->hdr->_csectFat; \ @@ -823,7 +815,7 @@ typedef struct CFB_Data * When 512 bytes sectors we don't care about _ulSizeHigh. */ -#define cfb_getNodeStreamLen( cfbd, node ) \ +#define CFB_getNodeStreamLen( cfbd, node ) \ (( cfbd->hdr->_uSectorShift > 9 ) ? \ (uint64_t)(( (uint64_t)(node->_ulSizeHigh) << 32 ) | ( node->_ulSizeLow )) : \ node->_ulSizeLow) @@ -831,8 +823,8 @@ typedef struct CFB_Data -#define cfb_getStreamSectorShift( cfbd, node ) \ - (( cfb_getNodeStreamLen( cfbd, node ) < cfbd->hdr->_ulMiniSectorCutoff ) ? \ +#define CFB_getStreamSectorShift( cfbd, node ) \ + (( CFB_getNodeStreamLen( cfbd, node ) < cfbd->hdr->_ulMiniSectorCutoff ) ? \ cfbd->hdr->_uMiniSectorShift : \ cfbd->hdr->_uSectorShift) @@ -842,9 +834,9 @@ typedef struct CFB_Data */ -const wchar_t * cfb_CLSIDToText( const cfbCLSID_t *clsid ); +const char * cfb_CLSIDToText( const cfbCLSID_t *clsid ); -wchar_t * cfb_w16towchar( wchar_t *buf, uint16_t *w16buf, size_t w16blen ); +char * cfb_w16toUTF8( const uint16_t *w16buf, size_t w16blen ); /** @@ -853,7 +845,7 @@ wchar_t * cfb_w16towchar( wchar_t *buf, uint16_t *w16buf, size_t w16blen ); * @{ */ -CFB_Data * cfb_alloc( struct dbg *dbg ); +CFB_Data * cfb_alloc( struct aafLog *log ); /** * @} @@ -892,7 +884,7 @@ uint64_t cfb_getStream( CFB_Data*cfbd, cfbNode*node, unsigned char **stream, uin int cfb__foreachSectorInStream( CFB_Data *cfbd, cfbNode *node, unsigned char **buf, size_t *bytesRead, cfbSectorID_t *sectID ); -#define cfb_foreachSectorInStream( cfbd, node, buf, bytesRead, sectID ) \ +#define CFB_foreachSectorInStream( cfbd, node, buf, bytesRead, sectID ) \ while ( cfb__foreachSectorInStream( cfbd, node, buf, bytesRead, sectID ) ) /** @@ -902,9 +894,9 @@ int cfb__foreachSectorInStream( CFB_Data *cfbd, cfbNode *node, unsigned char **b * @{ */ -cfbNode * cfb_getNodeByPath( CFB_Data *cfbd, const wchar_t *name, cfbSID_t id ); +cfbNode * cfb_getNodeByPath( CFB_Data *cfbd, const char *path, cfbSID_t id ); -cfbNode * cfb_getChildNode( CFB_Data *cfbd, const wchar_t *name, cfbNode *startNode ); +cfbNode * cfb_getChildNode( CFB_Data *cfbd, const char *name, cfbNode *startNode ); /** diff --git a/tools/common.h b/include/libaaf/MediaComposer.h similarity index 68% rename from tools/common.h rename to include/libaaf/MediaComposer.h index 3f92952..c7f3b49 100644 --- a/tools/common.h +++ b/include/libaaf/MediaComposer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -18,17 +18,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef __common_h__ -#define __common_h__ +#ifndef __MediaComposer_h__ +#define __MediaComposer_h__ -#ifdef __cplusplus -extern "C" { -#endif +#include +#include -void enable_windows_VT100_output( void ); -#ifdef __cplusplus -} -#endif +#define AVID_MEDIA_COMPOSER_CURVE_TYPE_LINEAR 0 +#define AVID_MEDIA_COMPOSER_CURVE_TYPE_EQUAL_POWER 1 -#endif // ! __common_h__ + +int mediaComposer_AAF( struct AAF_Iface *aafi ); + +#endif // !__MediaComposer_h__ diff --git a/include/libaaf/ProTools.h b/include/libaaf/ProTools.h index b85fede..a1d7d81 100644 --- a/include/libaaf/ProTools.h +++ b/include/libaaf/ProTools.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -26,11 +26,11 @@ enum protools_options { - PROTOOLS_REMOVE_SAMPLE_ACCURATE_EDIT = 1<<0, - PROTOOLS_REPLACE_CLIP_FADES = 1<<1, + AAFI_PROTOOLS_OPT_REMOVE_SAMPLE_ACCURATE_EDIT = 1<<0, + AAFI_PROTOOLS_OPT_REPLACE_CLIP_FADES = 1<<1, }; -#define PROTOOLS_ALL (PROTOOLS_REMOVE_SAMPLE_ACCURATE_EDIT | PROTOOLS_REPLACE_CLIP_FADES) +#define PROTOOLS_ALL_OPT (AAFI_PROTOOLS_OPT_REMOVE_SAMPLE_ACCURATE_EDIT | AAFI_PROTOOLS_OPT_REPLACE_CLIP_FADES) int protools_AAF( struct AAF_Iface *aafi ); diff --git a/include/libaaf/Resolve.h b/include/libaaf/Resolve.h index 5e44b0d..52d6c99 100644 --- a/include/libaaf/Resolve.h +++ b/include/libaaf/Resolve.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Adrien Gesta-Fline + * Copyright (C) 2023-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -25,18 +25,6 @@ #include -enum resolve_options { - RESOLVE_INCLUDE_DISABLED_CLIPS = 1<<0, -}; - -#define RESOLVE_ALL (RESOLVE_INCLUDE_DISABLED_CLIPS) - - int resolve_AAF( struct AAF_Iface *aafi ); -int resolve_parse_aafObject_Selector( struct AAF_Iface *aafi, aafObject *Selector, td *__ptd ); - -int resolve_parse_aafObject_DescriptiveMarker( struct AAF_Iface *aafi, aafObject *DescriptiveMarker, td *__ptd ); - - #endif // !__Resolve_h__ diff --git a/include/libaaf/debug.h b/include/libaaf/debug.h deleted file mode 100644 index 81507e0..0000000 --- a/include/libaaf/debug.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2017-2023 Adrien Gesta-Fline - * - * This file is part of libAAF. - * - * 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 __debug_h__ -#define __debug_h__ - -#include -#include -#include -#include - -#include - -#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) - - - -enum debug_source_id { - DEBUG_SRC_ID_LIB_CFB, - DEBUG_SRC_ID_AAF_CORE, - DEBUG_SRC_ID_AAF_IFACE, - DEBUG_SRC_ID_TRACE, - DEBUG_SRC_ID_DUMP -}; - - - -typedef enum verbosityLevel_e { - VERB_QUIET = 0, - VERB_ERROR, - VERB_WARNING, - VERB_DEBUG, - MAX_VERB -} verbosityLevel_e; - - - -struct dbg { - - void (*debug_callback)( struct dbg *dbg, void *ctxdata, int lib, int type, const char *srcfile, const char *srcfunc, int lineno, const char *msg, void *user ); - - FILE *fp; - verbosityLevel_e verb; - int ansicolor; - - char *_dbg_msg; - int _dbg_msg_size; - int _dbg_msg_pos; - - char *_dbg_msg_tmp; - int _dbg_msg_pos_tmp; - - void *user; -}; - - - -#define _dbg( dbg, ctxdata, lib, type, ... ) \ - { const char *dbgfile = __FILENAME__; const char *dbgfunc = __func__; int dbgline = __LINE__; \ - if ( dbg && dbg->verb >= type && dbg->debug_callback ) { \ - if ( dbg->_dbg_msg_pos ) { \ - dbg->_dbg_msg_pos_tmp = dbg->_dbg_msg_pos; \ - dbg->_dbg_msg_tmp = laaf_util_c99strdup( dbg->_dbg_msg ); \ - } \ - int msgsize = snprintf( NULL, 0, __VA_ARGS__ ) + 1; \ - if ( msgsize >= dbg->_dbg_msg_size ) { \ - char *msgtmp = realloc( dbg->_dbg_msg, msgsize ); \ - if ( msgtmp ) { \ - dbg->_dbg_msg = msgtmp; \ - dbg->_dbg_msg_size = msgsize; \ - snprintf( dbg->_dbg_msg, dbg->_dbg_msg_size, __VA_ARGS__ ); \ - dbg->debug_callback( dbg, (void*)ctxdata, lib, type, dbgfile, dbgfunc, dbgline, dbg->_dbg_msg, dbg->user ); \ - } else { \ - /* realloc() error */ \ - } \ - } else { \ - snprintf( dbg->_dbg_msg, dbg->_dbg_msg_size, __VA_ARGS__ ); \ - dbg->debug_callback( dbg, (void*)ctxdata, lib, type, dbgfile, dbgfunc, dbgline, dbg->_dbg_msg, dbg->user ); \ - } \ - if ( dbg->_dbg_msg_pos_tmp ) { \ - dbg->_dbg_msg_pos = dbg->_dbg_msg_pos_tmp; \ - strcpy( dbg->_dbg_msg, dbg->_dbg_msg_tmp ); \ - free( dbg->_dbg_msg_tmp ); \ - dbg->_dbg_msg_tmp = NULL; \ - dbg->_dbg_msg_pos_tmp = 0; \ - } \ - } \ - } \ - -#define DBG_BUFFER_WRITE( dbg, ... )\ - dbg->_dbg_msg_pos += laaf_util_snprintf_realloc( &dbg->_dbg_msg, &dbg->_dbg_msg_size, dbg->_dbg_msg_pos, __VA_ARGS__ ); - -#define DBG_BUFFER_RESET( dbg )\ - dbg->_dbg_msg_pos = 0; - - -struct dbg * laaf_new_debug( void ); - -void laaf_free_debug( struct dbg *dbg ); - -void laaf_debug_callback( struct dbg *dbg, void *ctxdata, int lib, int type, const char *srcfile, const char *srcfunc, int lineno, const char *msg, void *user ); - - -#endif // !__debug_h__ diff --git a/include/libaaf/log.h b/include/libaaf/log.h new file mode 100644 index 0000000..5b40537 --- /dev/null +++ b/include/libaaf/log.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2017-2024 Adrien Gesta-Fline + * + * This file is part of libAAF. + * + * 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 laaf_log_h__ +#define laaf_log_h__ + +#include +#include +#include +#include +#include // PRIi64 PRIu64 +#include + +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + + + +enum debug_source_id { + DEBUG_SRC_ID_LIB_CFB, + DEBUG_SRC_ID_AAF_CORE, + DEBUG_SRC_ID_AAF_IFACE, + DEBUG_SRC_ID_TRACE, + DEBUG_SRC_ID_DUMP +}; + + + +typedef enum verbosityLevel_e { + VERB_QUIET = 0, + VERB_ERROR, + VERB_WARNING, + VERB_DEBUG, + MAX_VERB +} verbosityLevel_e; + +#define VERB_SUCCESS 99 + + +struct aafLog { + + void (*debug_callback)( struct aafLog *log, void *ctxdata, int lib, int type, const char *srcfile, const char *srcfunc, int lineno, const char *msg, void *user ); + + FILE *fp; + verbosityLevel_e verb; + int ansicolor; + + const char * color_reset; + + char *_msg; + size_t _msg_size; + size_t _msg_pos; + + char *_previous_msg; + size_t _previous_pos; + + int _tmp_dbg_msg_pos; + + void *user; +}; + + +#define AAF_LOG( log, ctxdata, lib, type, ... ) \ + laaf_write_log( log, ctxdata, lib, type, __FILENAME__, __func__, __LINE__, __VA_ARGS__ ) + + +#define LOG_BUFFER_WRITE( log, ... )\ + log->_tmp_dbg_msg_pos = laaf_util_snprintf_realloc( &log->_msg, &log->_msg_size, log->_msg_pos, __VA_ARGS__ ); \ + log->_msg_pos += (log->_tmp_dbg_msg_pos<0) ? 0 : (size_t)log->_tmp_dbg_msg_pos; + +#define DBG_BUFFER_RESET( log )\ + log->_msg_pos = 0; + + +struct aafLog * laaf_new_log( void ); + +void laaf_free_log( struct aafLog *log ); + +void laaf_log_callback( struct aafLog *log, void *ctxdata, int lib, int type, const char *srcfile, const char *srcfunc, int lineno, const char *msg, void *user ); + +void laaf_write_log( struct aafLog *log, void *ctxdata, enum debug_source_id lib, enum verbosityLevel_e type, const char *dbgfile, const char *dbgfunc, int dbgline, const char *format, ... ); + +#endif // !laaf_log_h__ diff --git a/include/libaaf/utils.h b/include/libaaf/utils.h index 09dd9f4..5efeb61 100644 --- a/include/libaaf/utils.h +++ b/include/libaaf/utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -23,6 +23,7 @@ #include #include + #include #ifdef __cplusplus @@ -32,68 +33,81 @@ extern "C" { #ifdef _WIN32 #define DIR_SEP '\\' #define DIR_SEP_STR "\\" - /* - * swprintf() specific string format identifiers - * https://learn.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-170#type - */ - #define WPRIs L"S" // char* - #ifdef XBUILD_WIN - #define WPRIws L"s" // wchar_t* - #else - #define WPRIws L"ls" // wchar_t* - #endif #else #define DIR_SEP '/' #define DIR_SEP_STR "/" - /* - * swprintf() specific string format identifiers - * https://learn.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-170#type - */ - #define WPRIs L"s" // char* - #define WPRIws L"ls" // wchar_t* #endif +#if defined(__linux__) + #include + #include +#elif defined(__APPLE__) + #include +#elif defined(_WIN32) + #include // MAX_PATH + #include + #include +#endif + + + +#define AAF_DIR_SEP '/' +#define AAF_DIR_SEP_STR "/" + #define IS_DIR_SEP(c) \ (( ((c) == DIR_SEP) || ((c) == '/') )) +#define IS_ANY_DIR_SEP(c) \ + (( ((c) == '/') || ((c) == '\\') )) -#define ANSI_COLOR_RED( dbg ) (( (dbg)->ansicolor ) ? "\033[38;5;124m" : "") //"\x1b[31m" -#define ANSI_COLOR_GREEN( dbg ) (( (dbg)->ansicolor ) ? "\x1b[92m" : "") -#define ANSI_COLOR_YELLOW( dbg ) (( (dbg)->ansicolor ) ? "\x1b[33m" : "") //"\x1b[93m" -#define ANSI_COLOR_ORANGE( dbg ) (( (dbg)->ansicolor ) ? "\033[38;5;130m" : "") -#define ANSI_COLOR_BLUE( dbg ) (( (dbg)->ansicolor ) ? "\x1b[34m" : "") -#define ANSI_COLOR_MAGENTA( dbg ) (( (dbg)->ansicolor ) ? "\x1b[35m" : "") -#define ANSI_COLOR_CYAN( dbg ) (( (dbg)->ansicolor ) ? "\033[38;5;81m" : "") //"\x1b[36m" -#define ANSI_COLOR_DARKGREY( dbg ) (( (dbg)->ansicolor ) ? "\x1b[38;5;242m" : "") -#define ANSI_COLOR_BOLD( dbg ) (( (dbg)->ansicolor ) ? "\x1b[1m" : "") -#define ANSI_COLOR_RESET( dbg ) (( (dbg)->ansicolor ) ? "\x1b[0m" : "") +#define ANSI_COLOR_RED( log ) (( (log)->ansicolor ) ? "\x1b[38;5;124m" : "") +#define ANSI_COLOR_GREEN( log ) (( (log)->ansicolor ) ? "\x1b[92m" : "") +#define ANSI_COLOR_YELLOW( log ) (( (log)->ansicolor ) ? "\x1b[33m" : "") +#define ANSI_COLOR_ORANGE( log ) (( (log)->ansicolor ) ? "\x1b[38;5;130m" : "") +#define ANSI_COLOR_BLUE( log ) (( (log)->ansicolor ) ? "\x1b[34m" : "") +#define ANSI_COLOR_MAGENTA( log ) (( (log)->ansicolor ) ? "\x1b[35m" : "") +#define ANSI_COLOR_CYAN( log ) (( (log)->ansicolor ) ? "\x1b[38;5;81m" : "") +#define ANSI_COLOR_DARKGREY( log ) (( (log)->ansicolor ) ? "\x1b[38;5;242m" : "") +#define ANSI_COLOR_BOLD( log ) (( (log)->ansicolor ) ? "\x1b[1m" : "") +#define ANSI_COLOR_RESET( log ) (( (log)->ansicolor ) ? (log->color_reset) ? log->color_reset : "\x1b[0m" : "") -aafPosition_t laaf_util_converUnit( aafPosition_t value, aafRational_t *valueEditRate, aafRational_t *destEditRate ); +#define TREE_LINE "\xe2\x94\x82" /* │ */ +#define TREE_PADDED_LINE "\xe2\x94\x82\x20\x20" /* │ */ +#define TREE_ENTRY "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80" /* ├── */ +#define TREE_LAST_ENTRY "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80" /* └── */ -char * laaf_util_wstr2str( const wchar_t *wstr ); -wchar_t * laaf_util_str2wstr( const char *str ); +size_t laaf_util_utf8strCharLen( const char *u8str ); -int laaf_util_wstr_contains_nonlatin( const wchar_t *str ); +char *laaf_util_utf16Toutf8(const uint16_t *u16str); -char * laaf_util_clean_filename( char *filename ); +#ifdef _WIN32 +wchar_t * laaf_util_windows_utf8toutf16( const char *str ); +char * laaf_util_windows_utf16toutf8( const wchar_t *wstr ); +#endif + +int laaf_util_file_exists( const char *filepath ); -const char * laaf_util_fop_get_file( const char *filepath ); +char * laaf_util_clean_filename( char *filename ); -int laaf_util_fop_is_wstr_fileext( const wchar_t *filepath, const wchar_t *ext ); +int laaf_util_is_fileext( const char *filepath, const char *ext ); char * laaf_util_build_path( const char *sep, const char *first, ... ); -int laaf_util_snprintf_realloc( char **str, int *size, size_t offset, const char *format, ... ); +char * laaf_util_relative_path( const char *filepath, const char *refpath ); -int laaf_util_vsnprintf_realloc( char **str, int *size, int offset, const char *fmt, va_list *args ); +char * laaf_util_absolute_path( const char *relpath ); char * laaf_util_c99strdup( const char *src ); -int laaf_util_dump_hex( const unsigned char *stream, size_t stream_sz, char **buf, int *bufsz, int offset ); +int laaf_util_snprintf_realloc( char **str, size_t *size, size_t offset, const char *format, ... ); + +int laaf_util_vsnprintf_realloc( char **str, size_t *size, size_t offset, const char *fmt, va_list args ); + +int laaf_util_dump_hex( const unsigned char *stream, size_t stream_sz, char **buf, size_t *bufsz, size_t offset, const char *padding ); #ifdef __cplusplus diff --git a/src/AAFCore/AAFClass.c b/src/AAFCore/AAFClass.c index 9fb5454..6ab88ad 100644 --- a/src/AAFCore/AAFClass.c +++ b/src/AAFCore/AAFClass.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -39,35 +39,35 @@ #include #include -#include +#include #include "AAFClass.h" #define debug( ... ) \ - _dbg( aafd->dbg, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_DEBUG, __VA_ARGS__ ) + AAF_LOG( aafd->log, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_DEBUG, __VA_ARGS__ ) #define warning( ... ) \ - _dbg( aafd->dbg, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_WARNING, __VA_ARGS__ ) + AAF_LOG( aafd->log, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_WARNING, __VA_ARGS__ ) #define error( ... ) \ - _dbg( aafd->dbg, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_ERROR, __VA_ARGS__ ) + AAF_LOG( aafd->log, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_ERROR, __VA_ARGS__ ) #define attachNewProperty( aafd, Class, Prop, Pid, IsReq ) \ - Prop = calloc( sizeof(aafPropertyDef), sizeof(unsigned char) ); \ - if ( Prop == NULL ) { \ - error( "%s.", strerror( errno ) ); \ - return -1; \ - } \ - Prop->pid = Pid; \ - Prop->name = NULL; \ - Prop->isReq = IsReq; \ - Prop->meta = 0; \ - Prop->next = Class->Properties; \ - memset( &Prop->type, 0x00, sizeof(aafUID_t) ); \ - Class->Properties = Prop; \ + Prop = calloc( 1, sizeof(aafPropertyDef) ); \ + if ( !Prop ) { \ + error( "Out of memory" ); \ + return -1; \ + } \ + Prop->pid = Pid; \ + Prop->name = NULL; \ + Prop->isReq = IsReq; \ + Prop->meta = 0; \ + Prop->next = Class->Properties; \ + memset( &Prop->type, 0x00, sizeof(aafUID_t) ); \ + Class->Properties = Prop; \ @@ -79,7 +79,7 @@ int aafclass_classExists( AAF_Data *aafd, aafUID_t *ClassID ) if ( aafUIDCmp( Class->ID, ClassID ) ) break; - if ( Class == NULL ) + if ( !Class ) return 0; return 1; @@ -103,8 +103,8 @@ aafClass * aafclass_defineNewClass( AAF_Data *aafd, const aafUID_t *id, uint8_t { aafClass *Class = malloc( sizeof(aafClass) ); - if ( Class == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !Class ) { + error( "Out of memory" ); return NULL; } diff --git a/src/AAFCore/AAFCore.c b/src/AAFCore/AAFCore.c index 2eef02c..2c447d0 100644 --- a/src/AAFCore/AAFCore.c +++ b/src/AAFCore/AAFCore.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -33,7 +33,7 @@ #include #include -#include +#include #include "AAFClass.h" #include @@ -41,34 +41,13 @@ #define debug( ... ) \ - _dbg( aafd->dbg, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_DEBUG, __VA_ARGS__ ) + AAF_LOG( aafd->log, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_DEBUG, __VA_ARGS__ ) #define warning( ... ) \ - _dbg( aafd->dbg, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_WARNING, __VA_ARGS__ ) + AAF_LOG( aafd->log, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_WARNING, __VA_ARGS__ ) #define error( ... ) \ - _dbg( aafd->dbg, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_ERROR, __VA_ARGS__ ) - - - -/** - * Loops through each aafPropertyIndexEntry_t of a "properties" node stream. - * - * @param Header Pointer to the stream's aafPropertyIndexHeader_t struct. - * @param Entry Pointer that will receive each aafPropertyIndexEntry_t struct. - * @param Value Pointer to each property's data value, of aafPropertyIndexEntry_t._length - * bytes length. - * @param i uint32_t iterator. - */ - -#define foreachPropertyEntry( propStream, Header, Entry, Value, valueOffset, i ) \ - for ( valueOffset = sizeof(aafPropertyIndexHeader_t) + (Header._entryCount * sizeof(aafPropertyIndexEntry_t)), \ - i = 0; \ - i < Header._entryCount && \ - memcpy( &Entry, (propStream + ((sizeof(aafPropertyIndexHeader_t)) + (sizeof(aafPropertyIndexEntry_t) * i))), sizeof(aafPropertyIndexEntry_t) ) && \ - (Value = propStream + valueOffset); \ - valueOffset += Entry._length, \ - i++ ) + AAF_LOG( aafd->log, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_ERROR, __VA_ARGS__ ) @@ -104,9 +83,9 @@ #define attachNewProperty( Class, PDef, Pid, IsReq ) \ - PDef = calloc( sizeof(aafPropertyDef), sizeof(unsigned char) ); \ - if ( PDef == NULL ) { \ - error( "%s.", strerror( errno ) ); \ + PDef = calloc( 1, sizeof(aafPropertyDef) ); \ + if ( !PDef ) { \ + error( "Out of memory" ); \ return NULL; \ } \ PDef->pid = Pid; \ @@ -290,7 +269,7 @@ static int setObjectStrongRefVector( aafObject *Obj, aafStrongRefVectorHeader_t * @param parent Pointer to the parent Object which holds the Prop property. */ -static int retrieveStrongReference( AAF_Data *aafd, aafProperty *Prop, aafObject *parent ); +static int retrieveStrongReference( AAF_Data *aafd, aafProperty *Prop, aafObject *Parent ); @@ -303,7 +282,7 @@ static int retrieveStrongReference( AAF_Data *aafd, aafProperty *Prop, aafObject * @param parent Pointer to the parent Object which holds the Prop property. */ -static int retrieveStrongReferenceSet( AAF_Data *aafd, aafProperty *Prop, aafObject *parent ); + static int retrieveStrongReferenceSet( AAF_Data *aafd, aafProperty *Prop, aafObject *parent ); @@ -316,7 +295,7 @@ static int retrieveStrongReferenceSet( AAF_Data *aafd, aafProperty *Prop, aafObj * @param parent Pointer to the parent Object which holds the Prop property. */ -static int retrieveStrongReferenceVector( AAF_Data *aafd, aafProperty *Prop, aafObject *parent ); +static int retrieveStrongReferenceVector( AAF_Data *aafd, aafProperty *Prop, aafObject *Parent ); @@ -365,7 +344,7 @@ static int retrieveObjectProperties( AAF_Data *aafd, aafObject *Obj ); * @return Pointer to the retrieved Node cfbNode structure. */ -static cfbNode * getStrongRefIndexNode( AAF_Data *aafd, aafObject *parent, const wchar_t *refName ); +static cfbNode * getStrongRefIndexNode( AAF_Data *aafd, aafObject *Parent, const char *refName ); @@ -382,7 +361,7 @@ static cfbNode * getStrongRefIndexNode( AAF_Data *aafd, aafObject *parent, const * @return Pointer to the retrieved Node cfbNode structure. */ -static cfbNode * getStrongRefEntryNode( AAF_Data *aafd, aafObject *parent, const wchar_t *baseName, uint16_t index ); +static cfbNode * getStrongRefEntryNode( AAF_Data *aafd, aafObject *Parent, const char *refName, uint32_t index ); @@ -416,7 +395,7 @@ static aafByte_t * getNodeProperties( AAF_Data *aafd, cfbNode *node ); * aafStrongRefSetEntry_t structures. */ -static aafStrongRefSetHeader_t * getStrongRefSetList( AAF_Data *aafd, cfbNode *node, aafObject *parent ); +static aafStrongRefSetHeader_t * getStrongRefSetList( AAF_Data *aafd, cfbNode *Node, aafObject *Parent ); @@ -434,19 +413,19 @@ static aafStrongRefSetHeader_t * getStrongRefSetList( AAF_Data *aafd, cfbNode *n * _entryCount aafStrongRefVectorEntry_t structures. */ -static aafByte_t * getStrongRefVectorList( AAF_Data *aafd, cfbNode *node, aafObject *parent ); +static aafByte_t * getStrongRefVectorList( AAF_Data *aafd, cfbNode *Node, aafObject *Parent ); -AAF_Data *aaf_alloc( struct dbg *dbg ) +AAF_Data *aaf_alloc( struct aafLog *log ) { - AAF_Data *aafd = calloc( sizeof(AAF_Data), sizeof(unsigned char) ); + AAF_Data *aafd = calloc( 1, sizeof(AAF_Data) ); - if ( aafd == NULL ) - error( "%s.", strerror( errno ) ); + if ( !aafd ) { + goto err; + } aafd->cfbd = NULL; - // aafd->verb = VERB_QUIET; aafd->Identification.CompanyName = NULL; aafd->Identification.ProductName = NULL; @@ -455,26 +434,34 @@ AAF_Data *aaf_alloc( struct dbg *dbg ) aafd->Classes = NULL; aafd->Objects = NULL; - // aafd->debug_callback = &laaf_debug_callback; - aafd->dbg = dbg; + aafd->log = log; - aafd->cfbd = cfb_alloc( dbg ); + aafd->cfbd = cfb_alloc( log ); - if ( aafd->cfbd == NULL ) { - return NULL; + if ( !aafd->cfbd ) { + goto err; } - // aafd->cfbd->verb = aafd->verb; - return aafd; + +err: + + if ( aafd ) { + if ( aafd->cfbd ) { + cfb_release( &aafd->cfbd ); + } + free( aafd ); + } + + return NULL; } int aaf_load_file( AAF_Data *aafd, const char *file ) { - if ( file == NULL ) + if ( !aafd || !file ) return 1; aafd->Objects = NULL; @@ -518,7 +505,7 @@ int aaf_load_file( AAF_Data *aafd, const char *file ) void aaf_release( AAF_Data **aafd ) { - if ( aafd == NULL || *aafd == NULL ) + if ( !aafd || !(*aafd) ) return; @@ -536,19 +523,13 @@ void aaf_release( AAF_Data **aafd ) aafPropertyDef *PDef = NULL; aafPropertyDef *tmpPDef = NULL; - if ( Class->name != NULL ) { - free( Class->name ); - } + free( Class->name ); for ( PDef = Class->Properties; PDef != NULL; PDef = tmpPDef ) { tmpPDef = PDef->next; - // if ( PDef->meta ) { - if ( PDef->name != NULL ) - free( PDef->name ); - // } - + free( PDef->name ); free( PDef ); } @@ -563,12 +544,9 @@ void aaf_release( AAF_Data **aafd ) { tmpObject = Object->nextObj; - if ( Object->Header != NULL ) - free( Object->Header ); - - if ( Object->Entry != NULL ) - free( Object->Entry ); - + free( Object->Header ); + free( Object->Entry ); + free( Object->Name ); aafProperty *Prop = NULL; aafProperty *tmpProp = NULL; @@ -595,26 +573,10 @@ void aaf_release( AAF_Data **aafd ) } - if ( (*aafd)->Identification.CompanyName != NULL ) { - free( (*aafd)->Identification.CompanyName ); - } - - if ( (*aafd)->Identification.ProductName != NULL ) { - free( (*aafd)->Identification.ProductName ); - } - - if ( (*aafd)->Identification.ProductVersionString != NULL ) { - free( (*aafd)->Identification.ProductVersionString ); - } - - if ( (*aafd)->Identification.Platform != NULL ) { - free( (*aafd)->Identification.Platform ); - } - - /* free once in AAFIface */ - // if ( (*aafd)->dbg ) { - // laaf_free_debug( (*aafd)->dbg ); - // } + free( (*aafd)->Identification.CompanyName ); + free( (*aafd)->Identification.ProductName ); + free( (*aafd)->Identification.ProductVersionString ); + free( (*aafd)->Identification.Platform ); free( *aafd ); @@ -623,16 +585,16 @@ void aaf_release( AAF_Data **aafd ) -wchar_t * aaf_get_ObjectPath( aafObject *Obj ) +char * aaf_get_ObjectPath( aafObject *Obj ) { - static wchar_t path[CFB_PATH_NAME_SZ]; + static char path[CFB_PATH_NAME_SZ]; uint32_t offset = CFB_PATH_NAME_SZ; - path[--offset] = 0x0000; // NULL terminating byte + path[--offset] = '\0'; while ( Obj != NULL ) { - for ( int i = wcslen(Obj->Name)-1; i >= 0 && offset > 0; i-- ) { + for ( int i = (int)strlen(Obj->Name)-1; i >= 0 && offset > 0; i-- ) { path[--offset] = Obj->Name[i]; } @@ -651,7 +613,7 @@ wchar_t * aaf_get_ObjectPath( aafObject *Obj ) int _aaf_foreach_ObjectInSet( aafObject **Obj, aafObject *head, const aafUID_t *filter ) { - if ( *Obj == NULL ) + if ( !(*Obj) ) *Obj = head; else *Obj = (*Obj)->next; @@ -661,17 +623,14 @@ int _aaf_foreach_ObjectInSet( aafObject **Obj, aafObject *head, const aafUID_t * if ( aafUIDCmp( (*Obj)->Class->ID, filter ) ) break; - return ( *Obj == NULL ) ? 0 : 1; + return ( !(*Obj) ) ? 0 : 1; } aafObject * aaf_get_ObjectByWeakRef( aafObject *list, aafWeakRef_t *ref ) { - if ( ref == NULL || - list == NULL || - list->Entry == NULL ) - { + if ( !ref || !list || !list->Entry ) { return NULL; } @@ -714,18 +673,154 @@ aafObject * aaf_get_ObjectByWeakRef( aafObject *list, aafWeakRef_t *ref ) +aafUID_t * aaf_get_InterpolationIdentificationByWeakRef( AAF_Data *aafd, aafWeakRef_t *InterpolationDefWeakRef ) +{ + aafObject *InterpolationDefinition = aaf_get_ObjectByWeakRef( aafd->InterpolationDefinition, InterpolationDefWeakRef ); + + if ( !InterpolationDefinition ) { + error( "Could not find InterpolationDefinition." ); + return NULL; + } + + + aafUID_t *InterpolationIdentification = aaf_get_propertyValue( InterpolationDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID ); + + if ( !InterpolationIdentification ) { + error( "Missing DefinitionObject::Identification." ); + return NULL; + } + + + return InterpolationIdentification; +} + + + +aafUID_t * aaf_get_OperationIdentificationByWeakRef( AAF_Data *aafd, aafWeakRef_t *OperationDefWeakRef ) +{ + aafObject *OperationDefinition = aaf_get_ObjectByWeakRef( aafd->OperationDefinition, OperationDefWeakRef ); + + if ( !OperationDefinition ) { + error( "Could not retrieve OperationDefinition from dictionary." ); + return NULL; + } + + + aafUID_t *OperationIdentification = aaf_get_propertyValue( OperationDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID ); + + if ( !OperationIdentification ) { + error( "Missing DefinitionObject::Identification." ); + return NULL; + } + + + return OperationIdentification; +} + + + +aafUID_t * aaf_get_ContainerIdentificationByWeakRef( AAF_Data *aafd, aafWeakRef_t *ContainerDefWeakRef ) +{ + aafObject *ContainerDefinition = aaf_get_ObjectByWeakRef( aafd->ContainerDefinition, ContainerDefWeakRef ); + + if ( !ContainerDefinition ) { + warning( "Could not retrieve WeakRef from Dictionary::ContainerDefinitions." ); + return NULL; + } + + + aafUID_t *ContainerIdentification = aaf_get_propertyValue( ContainerDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID ); + + if ( !ContainerIdentification ) { + warning( "Missing ContainerDefinition's DefinitionObject::Identification." ); + return NULL; + } + + + return ContainerIdentification; +} + + + +aafUID_t * aaf_get_DataIdentificationByWeakRef( AAF_Data *aafd, aafWeakRef_t *DataDefWeakRef ) +{ + aafObject *DataDefinition = aaf_get_ObjectByWeakRef( aafd->DataDefinition, DataDefWeakRef ); + + if ( !DataDefinition ) { + warning( "Could not retrieve WeakRef from Dictionary::DataDefinition." ); + return NULL; + } + + + aafUID_t *DataIdentification = aaf_get_propertyValue( DataDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID ); + + if ( !DataIdentification ) { + warning( "Missing DataDefinition's DefinitionObject::Identification." ); + return NULL; + } + + + return DataIdentification; +} + + + +aafObject * aaf_get_ObjectAncestor( aafObject *Obj, const aafUID_t *ClassID ) +{ + /* + * NOTE : AAFClassID_ContentStorage is the container of Mob and EssenceData, + * not of Identification, Dictionary and MetaDictionary. If needed, the func + * should work for them too thanks to Obj != NULL. + */ + + while ( Obj != NULL && !aafUIDCmp( Obj->Class->ID, &AAFClassID_ContentStorage ) ) { + + if ( aafUIDCmp( ClassID, Obj->Class->ID ) ) { + return Obj; + } + + if ( aaf_ObjectInheritsClass( Obj, ClassID ) ) { + return Obj; + } + + Obj = Obj->Parent; + } + + return NULL; +} + + + +int aaf_ObjectInheritsClass( aafObject *Obj, const aafUID_t *classID ) +{ + // AAF_Data *aafd = Obj->aafd; + + aafClass *classObj = NULL; + foreachClassInheritance( classObj, Obj->Class ) { + if ( aafUIDCmp( classObj->ID, classID ) ) { + // debug( "%s is a parent of class %s", + // aaft_ClassIDToText( aafd, classObj->ID ), + // aaft_ClassIDToText( aafd, Obj->Class->ID ) ); + return 1; + } + } + return 0; +} + + + aafObject * aaf_get_MobByID( aafObject *Mobs, aafMobID_t *MobID ) { aafObject *Mob = NULL; - if ( MobID == NULL ) + if ( !MobID ) return NULL; - aaf_foreach_ObjectInSet( &Mob, Mobs, NULL ) { + AAF_foreach_ObjectInSet( &Mob, Mobs, NULL ) { aafMobID_t *Current = aaf_get_propertyValue( Mob, PID_Mob_MobID, &AAFTypeID_MobIDType ); - if ( Current == NULL || aafMobIDCmp( Current, MobID ) ) + if ( !Current || aafMobIDCmp( Current, MobID ) ) break; } @@ -738,11 +833,10 @@ aafObject * aaf_get_MobSlotBySlotID( aafObject *MobSlots, aafSlotID_t SlotID ) { aafObject *MobSlot = NULL; - aaf_foreach_ObjectInSet( &MobSlot, MobSlots, NULL ) { - + AAF_foreach_ObjectInSet( &MobSlot, MobSlots, NULL ) { aafSlotID_t *CurrentSlotID = aaf_get_propertyValue( MobSlot, PID_MobSlot_SlotID, &AAFTypeID_UInt32 ); - if ( CurrentSlotID == NULL || *CurrentSlotID == SlotID ) + if ( !CurrentSlotID || *CurrentSlotID == SlotID ) break; } @@ -751,11 +845,118 @@ aafObject * aaf_get_MobSlotBySlotID( aafObject *MobSlots, aafSlotID_t SlotID ) +aafObject * aaf_get_EssenceDataByMobID( AAF_Data *aafd, aafMobID_t *MobID ) +{ + aafMobID_t *DataMobID = NULL; + aafObject *EssenceData = NULL; + + for ( EssenceData = aafd->EssenceData; EssenceData != NULL; EssenceData = EssenceData->next ) { + + DataMobID = aaf_get_propertyValue( EssenceData, PID_EssenceData_MobID, &AAFTypeID_MobIDType ); + + if ( aafMobIDCmp( DataMobID, MobID ) ) + break; + } + + return EssenceData; +} + + + +aafUID_t * aaf_get_ParamDefIDByName( AAF_Data *aafd, const char *name ) +{ + aafUID_t *ParamDefIdent = NULL; + aafObject *ParameterDefinitions = aaf_get_propertyValue( aafd->Dictionary, PID_Dictionary_ParameterDefinitions, &AAFTypeID_ParameterDefinitionStrongReferenceSet ); + aafObject *ParameterDefinition = NULL; + + AAF_foreach_ObjectInSet( &ParameterDefinition, ParameterDefinitions, NULL ) { + + char *paramName = aaf_get_propertyValue( ParameterDefinition, PID_DefinitionObject_Name, &AAFTypeID_String ); + + if ( !paramName ) { + continue; + } + + if ( strcmp( paramName, name ) == 0 ) { + ParamDefIdent = aaf_get_propertyValue( ParameterDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID ); + free( paramName ); + break; + } + + free( paramName ); + } + + return ParamDefIdent; +} + + + +void * aaf_get_TaggedValueByName( AAF_Data *aafd, aafObject *TaggedValueVector, const char *name, const aafUID_t *type ) +{ + struct aafLog *log = aafd->log; + + aafObject *TaggedValue = NULL; + + AAF_foreach_ObjectInSet( &TaggedValue, TaggedValueVector, NULL ) { + + if ( !aafUIDCmp( TaggedValue->Class->ID, &AAFClassID_TaggedValue ) ) { + LOG_BUFFER_WRITE( log, " %sObject > %s\n", + ANSI_COLOR_RESET(log), + aaft_ClassIDToText( aafd, TaggedValue->Class->ID ) ); + continue; + } + + char *taggedName = aaf_get_propertyValue( TaggedValue, PID_TaggedValue_Name, &AAFTypeID_String ); + aafIndirect_t *taggedIndirect = aaf_get_propertyValue( TaggedValue, PID_TaggedValue_Value, &AAFTypeID_Indirect ); + + if ( strcmp( taggedName, name ) == 0 ) { + + if ( aafUIDCmp( &taggedIndirect->TypeDef, type ) ) { + + debug( "Found TaggedValue \"%s\" of type %s", + taggedName, + aaft_TypeIDToText( &taggedIndirect->TypeDef ) ); + + free( taggedName ); + + void *value = aaf_get_indirectValue( aafd, taggedIndirect, type ); + + return value; + } + + debug( "Got TaggedValue \"%s\" but of type %s instead of %s", + taggedName, + aaft_TypeIDToText( &taggedIndirect->TypeDef ), + aaft_TypeIDToText( type ) ); + } + // LOG_BUFFER_WRITE( log, " %sTagged > Name: %s%s%s%*s Value: %s(%s)%s %s%s%s", + // ANSI_COLOR_RESET(log), + // ANSI_COLOR_DARKGREY(log), + // (name) ? name : "", + // ANSI_COLOR_RESET(log), + // (name) ? (size_t)(24-(int)strlen(name)) : (size_t)(24-strlen("")), " ", + // ANSI_COLOR_DARKGREY(log), + // aaft_TypeIDToText( &taggedIndirect->TypeDef ), + // ANSI_COLOR_RESET(log), + // ANSI_COLOR_DARKGREY(log), + // aaft_IndirectValueToText( aafd, taggedIndirect ), + // ANSI_COLOR_RESET(log) ); + + free( taggedName ); + } + + debug( "TaggedValue not found \"%s\"", name ); + + return NULL; +} + + + /* * TODO Works when the property was retrieved from MetaDictionary. What if the property is standard ? */ -aafPID_t aaf_get_PropertyIDByName( AAF_Data *aafd, const wchar_t *name ) +aafPID_t aaf_get_PropertyIDByName( AAF_Data *aafd, const char *name ) { aafClass *Class = NULL; @@ -764,7 +965,7 @@ aafPID_t aaf_get_PropertyIDByName( AAF_Data *aafd, const wchar_t *name ) aafPropertyDef *PDef = NULL; foreachPropertyDefinition( PDef, Class->Properties ) { - if ( PDef->name != NULL && wcscmp( PDef->name, name ) == 0 ) { + if ( PDef->name != NULL && strcmp( PDef->name, name ) == 0 ) { return PDef->pid; } } @@ -775,9 +976,33 @@ aafPID_t aaf_get_PropertyIDByName( AAF_Data *aafd, const wchar_t *name ) +aafUID_t * aaf_get_OperationDefIDByName( AAF_Data *aafd, const char *OpDefName ) +{ + aafObject *OperationDefinitions = aaf_get_propertyValue( aafd->Dictionary, PID_Dictionary_OperationDefinitions, &AAFTypeID_OperationDefinitionStrongReferenceSet ); + aafObject *OperationDefinition = NULL; + + while ( _aaf_foreach_ObjectInSet( &OperationDefinition, OperationDefinitions, NULL ) ) { + + aafUID_t *OpDefIdent = aaf_get_propertyValue( OperationDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID ); + + char *name = aaf_get_propertyValue( OperationDefinition, PID_DefinitionObject_Name, &AAFTypeID_String ); + + if ( strcmp( name, OpDefName ) == 0 ) { + free( name ); + return OpDefIdent; + } + + free( name ); + } + + return NULL; +} + + + aafProperty * aaf_get_property( aafObject *Obj, aafPID_t pid ) { - if ( Obj == NULL ) + if ( !Obj ) return NULL; AAF_Data *aafd = Obj->aafd; @@ -789,19 +1014,28 @@ aafProperty * aaf_get_property( aafObject *Obj, aafPID_t pid ) break; - if ( Prop == NULL ) { + if ( !Prop ) { aafPropertyDef *PDef = aafclass_getPropertyDefinitionByID( Obj->Class, pid ); - if ( PDef == NULL ) { - warning( "Unknown property 0x%04x (%ls) of Class %ls", pid, aaft_PIDToText( aafd, pid ), aaft_ClassIDToText(aafd, Obj->Class->ID) ); + if ( !PDef ) { + warning( "Could not retrieve 0x%04x (%s) of Class %s", + pid, + aaft_PIDToText( aafd, pid ), + aaft_ClassIDToText(aafd, Obj->Class->ID) ); return NULL; } if ( PDef->isReq ) { - error( "Could not retrieve %ls required property 0x%04x (%ls)", aaft_ClassIDToText(aafd, Obj->Class->ID), pid, aaft_PIDToText(aafd, pid) ); + error( "Could not retrieve %s required property 0x%04x (%s)", + aaft_ClassIDToText(aafd, Obj->Class->ID), + pid, + aaft_PIDToText(aafd, pid) ); } else { - debug( "Could not retrieve %ls optional property 0x%04x (%ls)", aaft_ClassIDToText(aafd, Obj->Class->ID), pid, aaft_PIDToText(aafd, pid) ); + debug( "Could not retrieve %s optional property 0x%04x (%s)", + aaft_ClassIDToText(aafd, Obj->Class->ID), + pid, + aaft_PIDToText(aafd, pid) ); } } @@ -812,14 +1046,14 @@ aafProperty * aaf_get_property( aafObject *Obj, aafPID_t pid ) void * aaf_get_propertyValue( aafObject *Obj, aafPID_t pid, const aafUID_t *typeID ) { - if ( Obj == NULL ) { + if ( !Obj ) { return NULL; } AAF_Data *aafd = Obj->aafd; aafProperty *Prop = aaf_get_property( Obj, pid ); - if ( Prop == NULL ) { + if ( !Prop ) { return NULL; } @@ -838,11 +1072,14 @@ void * aaf_get_propertyValue( aafObject *Obj, aafPID_t pid, const aafUID_t *type if ( aafUIDCmp( typeID, &AAFTypeID_String ) ) { if ( ((uint16_t*)value)[(len/2)-1] != 0x0000 ) { - error( "Object %ls string property 0x%04x (%ls) does not end with NULL", aaft_ClassIDToText(aafd, Obj->Class->ID), pid, aaft_PIDToText(aafd, pid) ); + error( "Object %s string property 0x%04x (%s) does not end with NULL", + aaft_ClassIDToText(aafd, Obj->Class->ID), + pid, + aaft_PIDToText(aafd, pid) ); return NULL; } - return cfb_w16towchar( NULL, value, len ); + return cfb_w16toUTF8( value, len ); } if ( aafUIDCmp( typeID, &AAFTypeID_Indirect ) ) { @@ -856,7 +1093,10 @@ void * aaf_get_propertyValue( aafObject *Obj, aafPID_t pid, const aafUID_t *type aafIndirect_t *Indirect = value; if ( aafUIDCmp( &Indirect->TypeDef, &AAFTypeID_String ) && ((uint16_t*)value)[(len/2)-1] != 0x0000 ) { - error( "Object %ls Indirect::string property 0x%04x (%ls) does not end with NULL", aaft_ClassIDToText(aafd, Obj->Class->ID), pid, aaft_PIDToText(aafd, pid) ); + error( "Object %s Indirect::string property 0x%04x (%s) does not end with NULL", + aaft_ClassIDToText(aafd, Obj->Class->ID), + pid, + aaft_PIDToText(aafd, pid) ); return NULL; } } @@ -880,7 +1120,12 @@ void * aaf_get_propertyValue( aafObject *Obj, aafPID_t pid, const aafUID_t *type ( aafUIDCmp( typeID, &AAFTypeID_AUID ) && len != sizeof(aafUID_t) ) || ( aafUIDCmp( typeID, &AAFTypeID_MobIDType ) && len != sizeof(aafMobID_t) ) ) { - error( "Object %ls property 0x%04x (%ls) size (%u) does not match type %ls", aaft_ClassIDToText(aafd, Obj->Class->ID), pid, aaft_PIDToText(aafd, pid), len, aaft_TypeIDToText(typeID) ); + error( "Object %s property 0x%04x (%s) size (%u) does not match type %s", + aaft_ClassIDToText(aafd, Obj->Class->ID), + pid, + aaft_PIDToText(aafd, pid), + len, + aaft_TypeIDToText(typeID) ); return NULL; } @@ -891,13 +1136,15 @@ void * aaf_get_propertyValue( aafObject *Obj, aafPID_t pid, const aafUID_t *type void * aaf_get_indirectValue( AAF_Data *aafd, aafIndirect_t *Indirect, const aafUID_t *typeDef ) { - if ( Indirect == NULL ) { + if ( !Indirect ) { error( "Indirect is NULL" ); return NULL; } if ( typeDef && aafUIDCmp( &Indirect->TypeDef, typeDef ) == 0 ) { - error( "Requested Indirect value of type %ls but has type %ls", aaft_TypeIDToText(typeDef), aaft_TypeIDToText(&Indirect->TypeDef) ); + error( "Requested Indirect value of type %s but has type %s", + aaft_TypeIDToText(typeDef), + aaft_TypeIDToText(&Indirect->TypeDef) ); return NULL; } @@ -918,14 +1165,14 @@ void * aaf_get_indirectValue( AAF_Data *aafd, aafIndirect_t *Indirect, const aaf uint16_t *w16 = malloc( indirectValueSize ); - if ( w16 == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !w16 ) { + error( "Out of memory" ); return NULL; } memcpy( w16, Indirect->Value, indirectValueSize ); - wchar_t *str = cfb_w16towchar( NULL, w16, indirectValueSize ); + char *str = cfb_w16toUTF8( w16, indirectValueSize ); free( w16 ); @@ -941,7 +1188,7 @@ static int parse_Header( AAF_Data *aafd ) { aafObject *Header = aafd->Header.obj; - if ( Header == NULL ) { + if ( !Header ) { error( "Missing Header Object." ); return -1; } @@ -949,7 +1196,7 @@ static int parse_Header( AAF_Data *aafd ) int16_t *ByteOrder = aaf_get_propertyValue( Header, PID_Header_ByteOrder, &AAFTypeID_Int16 ); - if ( ByteOrder == NULL ) { + if ( !ByteOrder ) { warning( "Missing Header::ByteOrder." ); } else { aafd->Header.ByteOrder = *ByteOrder; @@ -958,7 +1205,7 @@ static int parse_Header( AAF_Data *aafd ) aafTimeStamp_t *LastModified = aaf_get_propertyValue( Header, PID_Header_LastModified, &AAFTypeID_TimeStamp ); - if ( LastModified == NULL ) { + if ( !LastModified ) { warning( "Missing Header::LastModified." ); } else { aafd->Header.LastModified = LastModified; @@ -967,7 +1214,7 @@ static int parse_Header( AAF_Data *aafd ) aafVersionType_t *Version = aaf_get_propertyValue( Header, PID_Header_Version, &AAFTypeID_VersionType ); - if ( Version == NULL ) { + if ( !Version ) { warning( "Missing Header::Version." ); } else { aafd->Header.Version = Version; @@ -976,7 +1223,7 @@ static int parse_Header( AAF_Data *aafd ) uint32_t *ObjectModelVersion = aaf_get_propertyValue( Header, PID_Header_ObjectModelVersion, &AAFTypeID_UInt32 ); - if ( ObjectModelVersion == NULL ) { + if ( !ObjectModelVersion ) { warning( "Missing Header::ObjectModelVersion." ); } else { aafd->Header.ObjectModelVersion = *ObjectModelVersion; @@ -985,7 +1232,7 @@ static int parse_Header( AAF_Data *aafd ) const aafUID_t *OperationalPattern = aaf_get_propertyValue( Header, PID_Header_OperationalPattern, &AAFTypeID_AUID ); - if ( OperationalPattern == NULL ) { + if ( !OperationalPattern ) { warning( "Missing Header::OperationalPattern." ); aafd->Header.OperationalPattern = (const aafUID_t*)&AUID_NULL; } else { @@ -1002,24 +1249,24 @@ static int parse_Identification( AAF_Data *aafd ) { aafObject *Identif = aafd->Identification.obj; - if ( Identif == NULL ) { + if ( !Identif ) { error( "Missing Identification Object." ); return -1; } - wchar_t *Company = aaf_get_propertyValue( Identif, PID_Identification_CompanyName, &AAFTypeID_String ); + char *Company = aaf_get_propertyValue( Identif, PID_Identification_CompanyName, &AAFTypeID_String ); - if ( Company == NULL ) { + if ( !Company ) { warning( "Missing Identification::CompanyName." ); } else { aafd->Identification.CompanyName = Company; } - wchar_t *ProductName = aaf_get_propertyValue( Identif, PID_Identification_ProductName, &AAFTypeID_String ); + char *ProductName = aaf_get_propertyValue( Identif, PID_Identification_ProductName, &AAFTypeID_String ); - if ( ProductName == NULL ) { + if ( !ProductName ) { warning( "Missing Identification::ProductName." ); } else { aafd->Identification.ProductName = ProductName; @@ -1028,16 +1275,16 @@ static int parse_Identification( AAF_Data *aafd ) aafProductVersion_t *ProductVersion = aaf_get_propertyValue( Identif, PID_Identification_ProductVersion, &AAFTypeID_ProductVersion ); - if ( ProductVersion == NULL ) { + if ( !ProductVersion ) { warning( "Missing Identification::ProductVersion." ); } else { aafd->Identification.ProductVersion = ProductVersion; } - wchar_t *ProductVersionString = aaf_get_propertyValue( Identif, PID_Identification_ProductVersionString, &AAFTypeID_String ); + char *ProductVersionString = aaf_get_propertyValue( Identif, PID_Identification_ProductVersionString, &AAFTypeID_String ); - if ( ProductVersionString == NULL ) { + if ( !ProductVersionString ) { warning( "Missing Identification::ProductVersionString." ); } else { aafd->Identification.ProductVersionString = ProductVersionString; @@ -1046,7 +1293,7 @@ static int parse_Identification( AAF_Data *aafd ) aafUID_t *ProductID = aaf_get_propertyValue( Identif, PID_Identification_ProductID, &AAFTypeID_AUID ); - if ( ProductID == NULL ) { + if ( !ProductID ) { warning( "Missing Identification::ProductID." ); } else { aafd->Identification.ProductID = ProductID; @@ -1055,7 +1302,7 @@ static int parse_Identification( AAF_Data *aafd ) aafTimeStamp_t *Date = aaf_get_propertyValue( Identif, PID_Identification_Date, &AAFTypeID_TimeStamp ); - if ( Date == NULL ) { + if ( !Date ) { warning( "Missing Identification::Date." ); } else { aafd->Identification.Date = Date; @@ -1064,16 +1311,16 @@ static int parse_Identification( AAF_Data *aafd ) aafProductVersion_t *ToolkitVersion = aaf_get_propertyValue( Identif, PID_Identification_ToolkitVersion, &AAFTypeID_ProductVersion ); - if ( ToolkitVersion == NULL ) { + if ( !ToolkitVersion ) { warning( "Missing Identification::ToolkitVersion." ); } else { aafd->Identification.ToolkitVersion = ToolkitVersion; } - wchar_t *Platform = aaf_get_propertyValue( Identif, PID_Identification_Platform, &AAFTypeID_String ); + char *Platform = aaf_get_propertyValue( Identif, PID_Identification_Platform, &AAFTypeID_String ); - if ( Platform == NULL ) { + if ( !Platform ) { warning( "Missing Identification::Platform." ); } else { aafd->Identification.Platform = Platform; @@ -1082,7 +1329,7 @@ static int parse_Identification( AAF_Data *aafd ) aafUID_t *GenerationAUID = aaf_get_propertyValue( Identif, PID_Identification_GenerationAUID, &AAFTypeID_AUID ); - if ( GenerationAUID == NULL ) { + if ( !GenerationAUID ) { warning( "Missing Identification::GenerationAUID." ); } else { aafd->Identification.GenerationAUID = GenerationAUID; @@ -1102,7 +1349,7 @@ static int parse_Identification( AAF_Data *aafd ) // aafUIDCmp( hdrClsID, &AAFFileKind_Aaf4KBinary ) ) // return 1; // -// // warning( "Unsuported AAF encoding (%ls).", aaft_FileKindToText( hdrClsID ) ); +// // warning( "Unsuported AAF encoding (%s).", aaft_FileKindToText( hdrClsID ) ); // // return 0; // } @@ -1149,27 +1396,22 @@ static int retrieveObjectTree( AAF_Data *aafd ) aafClass *Class = aafclass_getClassByID( aafd, (aafUID_t*)&Node->_clsId ); - - if ( Class == NULL && aafUIDCmp( Class->ID, (aafUID_t*)&Node->_clsId ) != 0 ) { - error( "Looks like the fist Object is not the Root Class : %ls.", aaft_ClassIDToText( aafd, Class->ID ) ); + if ( !Class ) { + error( "Could not retrieve class by id" ); goto err; } - aafd->Root = newObject( aafd, Node, Class, NULL ); - if ( aafd->Root == NULL ) { + if ( !aafd->Root ) { goto err; } - - /* retrieveObjectProperties() */ - propStream = getNodeProperties( aafd, aafd->Root->Node ); - if ( propStream == NULL ) { - error( "Could not retrieve properties for %ls.", aaf_get_ObjectPath( aafd->Root ) ); + if ( !propStream ) { + error( "Could not retrieve properties for %s.", aaf_get_ObjectPath( aafd->Root ) ); goto err; } @@ -1191,7 +1433,7 @@ static int retrieveObjectTree( AAF_Data *aafd ) uint32_t i = 0; - int valueOffset = 0; + size_t valueOffset = 0; foreachPropertyEntry( propStream, Header, Prop, value, valueOffset, i ) { @@ -1213,7 +1455,7 @@ static int retrieveObjectTree( AAF_Data *aafd ) rc = retrieveProperty( aafd, aafd->Root, PDef, &AAFMetaDcProp, AAFMetaDcVal, Header._byteOrder ); if ( rc < 0 ) { - error( "Could not retrieve property %ls.", aaft_PIDToText( aafd, PDef->pid ) ); + error( "Could not retrieve property %s.", aaft_PIDToText( aafd, PDef->pid ) ); goto err; } @@ -1224,7 +1466,7 @@ static int retrieveObjectTree( AAF_Data *aafd ) aafObject *MetaDic = aaf_get_propertyValue( aafd->Root, PID_Root_MetaDictionary, &AAFUID_NULL ); - if ( MetaDic == NULL ) { + if ( !MetaDic ) { error( "Missing PID_Root_MetaDictionary." ); goto err; } @@ -1232,7 +1474,7 @@ static int retrieveObjectTree( AAF_Data *aafd ) aafObject *ClassDefs = aaf_get_propertyValue( MetaDic, PID_MetaDictionary_ClassDefinitions, &AAFTypeID_ClassDefinitionStrongReferenceSet ); - if ( ClassDefs == NULL ) { + if ( !ClassDefs ) { error( "Missing PID_MetaDictionary_ClassDefinitions." ); goto err; } @@ -1240,7 +1482,7 @@ static int retrieveObjectTree( AAF_Data *aafd ) aafObject *ClassDef = NULL; - aaf_foreach_ObjectInSet( &ClassDef, ClassDefs, NULL ) { + AAF_foreach_ObjectInSet( &ClassDef, ClassDefs, NULL ) { retrieveMetaDictionaryClass( aafd, ClassDef ); } @@ -1252,7 +1494,7 @@ static int retrieveObjectTree( AAF_Data *aafd ) rc = retrieveProperty( aafd, aafd->Root, PDef, &AAFHeaderProp, AAFHeaderVal, Header._byteOrder ); if ( rc < 0 ) { - error( "Could not retrieve property %ls.", aaft_PIDToText( aafd, PDef->pid ) ); + error( "Could not retrieve property %s.", aaft_PIDToText( aafd, PDef->pid ) ); goto err; } @@ -1267,8 +1509,7 @@ static int retrieveObjectTree( AAF_Data *aafd ) end: - if ( propStream ) - free( propStream ); + free( propStream ); return rc; } @@ -1279,31 +1520,50 @@ static aafClass * retrieveMetaDictionaryClass( AAF_Data *aafd, aafObject *Target { aafObject *MetaDic = aaf_get_propertyValue( aafd->Root, PID_Root_MetaDictionary, &AAFUID_NULL ); + if ( !MetaDic ) { /* req */ + debug( "Could not retrieve PID_Root_MetaDictionary property from Root." ); + return NULL; + } aafObject *ClassDefs = aaf_get_propertyValue( MetaDic, PID_MetaDictionary_ClassDefinitions, &AAFTypeID_ClassDefinitionStrongReferenceSet ); aafObject *ClassDef = NULL; - if ( ClassDefs == NULL ) { - error( "Could not retrieve PID_MetaDictionary_ClassDefinitions property from MetaDic." ); + if ( !ClassDefs ) { /* opt */ + debug( "Could not retrieve PID_MetaDictionary_ClassDefinitions property from MetaDic." ); return NULL; } - aaf_foreach_ObjectInSet( &ClassDef, ClassDefs, NULL ) { + AAF_foreach_ObjectInSet( &ClassDef, ClassDefs, NULL ) { if ( ClassDef == TargetClassDef ) break; } - if ( ClassDef == NULL ) { - error( "Could not retrieve ClassDefinition %p.", (void*)TargetClassDef ); + if ( !ClassDef ) { + error( "Could not retrieve ClassDefinition %p", (void*)TargetClassDef ); return NULL; } - aafUID_t *ClassID = aaf_get_propertyValue( ClassDef, PID_MetaDefinition_Identification, &AAFTypeID_AUID ); + aafUID_t *ClassID = aaf_get_propertyValue( ClassDef, PID_MetaDefinition_Identification, &AAFTypeID_AUID ); + + if ( !ClassID ) { /* req */ + error( "Could not retrieve PID_MetaDefinition_Identification property from ClassDef." ); + return NULL; + } aafWeakRef_t *parent = aaf_get_propertyValue( ClassDef, PID_ClassDefinition_ParentClass, &AAFTypeID_ClassDefinitionWeakReference ); - aafObject *Parent = aaf_get_ObjectByWeakRef( ClassDefs, parent ); + if ( !parent ) { + error( "Could not retrieve PID_ClassDefinition_ParentClass property from ClassDef." ); + return NULL; + } + + aafObject *Parent = aaf_get_ObjectByWeakRef( ClassDefs, parent ); + + if ( !Parent ) { + error( "Could not retrieve object by weakRef (PID_ClassDefinition_ParentClass)" ); + return NULL; + } aafClass *ParentClass = NULL; @@ -1317,42 +1577,62 @@ static aafClass * retrieveMetaDictionaryClass( AAF_Data *aafd, aafObject *Target /* * TODO: what is this ? when does it happen ? */ - error( "Parent's Class equals Child's : %ls.", aaft_ClassIDToText( aafd, ClassID ) ); + error( "Parent's Class equals Child's : %s.", aaft_ClassIDToText( aafd, ClassID ) ); return NULL; } aafClass *Class = aafclass_getClassByID( aafd, ClassID ); - if ( Class == NULL ) { + if ( !Class ) { aafBoolean_t *isCon = aaf_get_propertyValue( ClassDef, PID_ClassDefinition_IsConcrete, &AAFTypeID_Boolean ); - if ( isCon == NULL ) { + if ( !isCon ) { error( "Missing ClassDefinition::IsConcrete." ); return NULL; } Class = aafclass_defineNewClass( aafd, ClassID, *isCon, ParentClass ); - Class->name = aaf_get_propertyValue( ClassDef, PID_MetaDefinition_Name, &AAFTypeID_String ); + if ( !Class ) { + error( "Could set new class" ); + return NULL; + } + Class->meta = 1; + Class->name = aaf_get_propertyValue( ClassDef, PID_MetaDefinition_Name, &AAFTypeID_String ); + + if ( !Class->name ) { + debug( "Could not retrieve PID_MetaDefinition_Name property from ClassDef (%s)", aaft_ClassIDToText( aafd, ClassID ) ); + } } - else { // if class is standard, we only set its name - if ( Class->name == NULL ) { + else { + /* if class is standard, we only set its name */ + if ( !Class->name ) { + Class->name = aaf_get_propertyValue( ClassDef, PID_MetaDefinition_Name, &AAFTypeID_String ); + + if ( !Class->name ) { + debug( "Could not retrieve PID_MetaDefinition_Name property from ClassDef (%s)", aaft_ClassIDToText( aafd, ClassID ) ); + } } } aafObject *Props = aaf_get_propertyValue( ClassDef, PID_ClassDefinition_Properties, &AAFTypeID_PropertyDefinitionStrongReferenceSet ); + + if ( !Props ) { /* opt */ + debug( "Could not retrieve PID_ClassDefinition_Properties property from ClassDef (%s)", aaft_ClassIDToText( aafd, ClassID ) ); + } + aafObject *Prop = NULL; - aaf_foreach_ObjectInSet( &Prop, Props, NULL ) { + AAF_foreach_ObjectInSet( &Prop, Props, NULL ) { aafPID_t *Pid = aaf_get_propertyValue( Prop, PID_PropertyDefinition_LocalIdentification, &AAFTypeID_UInt16 ); - if ( Pid == NULL ) { + if ( !Pid ) { error( "Missing PropertyDefinition::LocalIdentification." ); return NULL; } @@ -1360,7 +1640,7 @@ static aafClass * retrieveMetaDictionaryClass( AAF_Data *aafd, aafObject *Target aafBoolean_t *isOpt = aaf_get_propertyValue( Prop, PID_PropertyDefinition_IsOptional, &AAFTypeID_Boolean ); - if ( isOpt == NULL ) { + if ( !isOpt ) { error( "Missing PropertyDefinition::IsOptional." ); return NULL; } @@ -1369,9 +1649,9 @@ static aafClass * retrieveMetaDictionaryClass( AAF_Data *aafd, aafObject *Target * We skip all the properties that were already defined in aafclass_setDefaultClasses(). */ - aafPropertyDef *PDef = NULL; + aafPropertyDef *PDef = propertyIdExistsInClass( Class, *Pid ); - if ( !(PDef = propertyIdExistsInClass( Class, *Pid )) ) { + if ( !PDef ) { attachNewProperty( Class, PDef, *Pid, ( *isOpt ) ? 0 : 1 ); PDef->meta = 1; } @@ -1382,10 +1662,14 @@ static aafClass * retrieveMetaDictionaryClass( AAF_Data *aafd, aafObject *Target PDef->name = aaf_get_propertyValue( Prop, PID_MetaDefinition_Name, &AAFTypeID_String ); + if ( !PDef->name ) { + warning( "Could not retrieve PID_MetaDefinition_Name property from PropertyDefinition." ); + } + aafObject *TypeDefs = aaf_get_propertyValue( MetaDic, PID_MetaDictionary_TypeDefinitions, &AAFTypeID_TypeDefinitionStrongReferenceSet ); - if ( TypeDefs == NULL ) { + if ( !TypeDefs ) { error( "Missing TypeDefinitions from MetaDictionary" ); return NULL; } @@ -1393,7 +1677,7 @@ static aafClass * retrieveMetaDictionaryClass( AAF_Data *aafd, aafObject *Target aafWeakRef_t *WeakRefToType = aaf_get_propertyValue( Prop, PID_PropertyDefinition_Type, &AAFTypeID_PropertyDefinitionWeakReference ); - if ( WeakRefToType == NULL ) { + if ( !WeakRefToType ) { error( "Missing PID_PropertyDefinition_Type" ); return NULL; } @@ -1401,7 +1685,7 @@ static aafClass * retrieveMetaDictionaryClass( AAF_Data *aafd, aafObject *Target aafObject *TypeDef = aaf_get_ObjectByWeakRef( TypeDefs, WeakRefToType ); - if ( TypeDef == NULL ) { + if ( !TypeDef ) { error( "Could not retrieve TypeDefinition from dictionary." ); return NULL; } @@ -1409,23 +1693,22 @@ static aafClass * retrieveMetaDictionaryClass( AAF_Data *aafd, aafObject *Target aafUID_t *typeUID = aaf_get_propertyValue( TypeDef, PID_MetaDefinition_Identification, &AAFTypeID_AUID ); - if ( typeUID == NULL ) { + if ( !typeUID ) { /* req */ error( "Missing PID_MetaDefinition_Identification" ); return NULL; } /* - * Looks like nobody cares about AAF standard TypeDefinition. All observed files + * Looks like nobody cares about AAF standard TypeDefinition. All observed files * had incorrect values for Type Name and Identification, even Avid's files. So... */ memcpy( &PDef->type, typeUID, sizeof(aafUID_t) ); - // wchar_t *typeName = aaf_get_propertyValue( TypeDef, PID_MetaDefinition_Name, &AAFTypeID_String ); + // char *typeName = aaf_get_propertyValue( TypeDef, PID_MetaDefinition_Name, &AAFTypeID_String ); // - // debug( "TypeName : %ls (%ls) | name : %ls.", - // // AUIDToText(typeUID), + // debug( "TypeName : %s (%s) | name : %s.", // typeName, // aaft_TypeIDToText( typeUID ), // PDef->name ); @@ -1440,15 +1723,14 @@ static aafClass * retrieveMetaDictionaryClass( AAF_Data *aafd, aafObject *Target static aafObject * newObject( AAF_Data *aafd, cfbNode *Node, aafClass *Class, aafObject *Parent ) { - aafObject *Obj = calloc( sizeof(aafObject), sizeof(unsigned char) ); + aafObject *Obj = calloc( 1, sizeof(aafObject) ); - if ( Obj == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !Obj ) { + error( "Out of memory" ); return NULL; } - cfb_w16towchar( Obj->Name, Node->_ab, Node->_cb ); - + Obj->Name = cfb_w16toUTF8( Node->_ab, Node->_cb ); Obj->aafd = aafd; Obj->Class = Class; Obj->Node = Node; @@ -1469,10 +1751,10 @@ static aafObject * newObject( AAF_Data *aafd, cfbNode *Node, aafClass *Class, aa static aafProperty * newProperty( AAF_Data *aafd, aafPropertyDef *Def ) { - aafProperty *Prop = calloc( sizeof(aafProperty), sizeof(unsigned char) ); + aafProperty *Prop = calloc( 1, sizeof(aafProperty) ); - if ( Prop == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !Prop ) { + error( "Out of memory" ); return NULL; } @@ -1503,8 +1785,8 @@ static int setObjectStrongRefSet( aafObject *Obj, aafStrongRefSetHeader_t *Heade Obj->Header = malloc( sizeof(aafStrongRefSetHeader_t) ); - if ( Obj->Header == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !Obj->Header ) { + error( "Out of memory" ); return -1; } @@ -1516,8 +1798,8 @@ static int setObjectStrongRefSet( aafObject *Obj, aafStrongRefSetHeader_t *Heade Obj->Entry = malloc( entrySize ); - if ( Obj->Entry == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !Obj->Entry ) { + error( "Out of memory" ); return -1; } @@ -1539,20 +1821,20 @@ static int setObjectStrongRefVector( aafObject *Obj, aafStrongRefVectorHeader_t AAF_Data *aafd = Obj->aafd; - Obj->Header = calloc( sizeof(aafStrongRefSetHeader_t), sizeof(unsigned char) ); + Obj->Header = calloc( 1, sizeof(aafStrongRefSetHeader_t) ); - if ( Obj->Header == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !Obj->Header ) { + error( "Out of memory" ); return -1; } memcpy( Obj->Header, Header, sizeof(aafStrongRefVectorHeader_t) ); - Obj->Entry = calloc( sizeof(aafStrongRefSetEntry_t), sizeof(unsigned char) ); + Obj->Entry = calloc( 1, sizeof(aafStrongRefSetEntry_t) ); - if ( Obj->Entry == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !Obj->Entry ) { + error( "Out of memory" ); return -1; } @@ -1567,21 +1849,21 @@ static int setObjectStrongRefVector( aafObject *Obj, aafStrongRefVectorHeader_t static int retrieveStrongReference( AAF_Data *aafd, aafProperty *Prop, aafObject *Parent ) { /* - * Initial property value is a wchar string holding the name of a child node. - * This child node being the object referenced, we store that object dirctly + * Initial property value is a unicode string holding the name of a child node. + * This child node being the object referenced, we store that object directly * as the property value, instead of the initial child node name. */ - wchar_t name[CFB_NODE_NAME_SZ]; - - cfb_w16towchar( name, Prop->val, Prop->len ); + char *name = cfb_w16toUTF8( Prop->val, Prop->len ); free( Prop->val ); Prop->val = NULL; cfbNode *Node = cfb_getChildNode( aafd->cfbd, name, Parent->Node ); - if ( Node == NULL ) { + free( name ); + + if ( !Node ) { error( "Could not find child node." ); return -1; } @@ -1589,15 +1871,17 @@ static int retrieveStrongReference( AAF_Data *aafd, aafProperty *Prop, aafObject aafClass *Class = aafclass_getClassByID( aafd, (aafUID_t*)&Node->_clsId ); - if ( Class == NULL ) { - error( "Could not retrieve Class %ls @ \"%ls\".", aaft_ClassIDToText( aafd, (aafUID_t*)&Node->_clsId ), aaf_get_ObjectPath( Parent ) ); + if ( !Class ) { + error( "Could not retrieve Class %s @ \"%s\".", + aaft_ClassIDToText( aafd, (aafUID_t*)&Node->_clsId ), + aaf_get_ObjectPath( Parent ) ); return -1; } Prop->val = newObject( aafd, Node, Class, Parent ); - if ( Prop->val == NULL ) { + if ( !Prop->val ) { return -1; } @@ -1618,9 +1902,7 @@ static int retrieveStrongReferenceSet( AAF_Data *aafd, aafProperty *Prop, aafObj aafStrongRefSetHeader_t *Header = NULL; aafStrongRefSetEntry_t *Entry = NULL; - wchar_t refName[CFB_NODE_NAME_SZ]; - - cfb_w16towchar( refName, Prop->val, Prop->len ); + char *refName = cfb_w16toUTF8( Prop->val, Prop->len ); free( Prop->val ); Prop->val = NULL; @@ -1628,14 +1910,14 @@ static int retrieveStrongReferenceSet( AAF_Data *aafd, aafProperty *Prop, aafObj cfbNode * Node = getStrongRefIndexNode( aafd, Parent, refName ); - if ( Node == NULL ) { + if ( !Node ) { error( "Could not retrieve StrongReferenceSet's Index node." ); goto err; } Header = getStrongRefSetList( aafd, Node, Parent ); - if ( Header == NULL ) { + if ( !Header ) { error( "Could not retrieve StrongReferenceSet's CFB Stream." ); goto err; } @@ -1643,8 +1925,8 @@ static int retrieveStrongReferenceSet( AAF_Data *aafd, aafProperty *Prop, aafObj Entry = malloc( sizeof(aafStrongRefSetEntry_t) + Header->_identificationSize ); - if ( Entry == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !Entry ) { + error( "Out of memory" ); goto err; } @@ -1658,20 +1940,21 @@ static int retrieveStrongReferenceSet( AAF_Data *aafd, aafProperty *Prop, aafObj Node = getStrongRefEntryNode( aafd, Parent, refName, Entry->_localKey ); - if ( Node == NULL ) { + if ( !Node ) { continue; } aafClass *Class = aafclass_getClassByID( aafd, (aafUID_t*)&Node->_clsId ); - if ( Class == NULL ) { - error( "Could not retrieve Class %ls.", aaft_ClassIDToText( aafd, (aafUID_t*)&Node->_clsId ) ); + if ( !Class ) { + error( "Could not retrieve Class %s.", + aaft_ClassIDToText( aafd, (aafUID_t*)&Node->_clsId ) ); continue; } aafObject * Obj = newObject( aafd, Node, Class, Parent ); - if ( Obj == NULL ) { + if ( !Obj ) { goto err; } @@ -1699,11 +1982,9 @@ static int retrieveStrongReferenceSet( AAF_Data *aafd, aafProperty *Prop, aafObj end: - if ( Header ) - free( Header ); - - if ( Entry ) - free( Entry ); + free( refName ); + free( Header ); + free( Entry ); return rc; } @@ -1715,9 +1996,7 @@ static int retrieveStrongReferenceVector( AAF_Data *aafd, aafProperty *Prop, aaf int rc = 0; aafByte_t *vectorStream = NULL; - wchar_t refName[CFB_NODE_NAME_SZ]; - - cfb_w16towchar( refName, Prop->val, Prop->len ); + char *refName = cfb_w16toUTF8( Prop->val, Prop->len ); free( Prop->val ); Prop->val = NULL; @@ -1725,14 +2004,14 @@ static int retrieveStrongReferenceVector( AAF_Data *aafd, aafProperty *Prop, aaf cfbNode * Node = getStrongRefIndexNode( aafd, Parent, refName ); - if ( Node == NULL ) { + if ( !Node ) { goto err; } vectorStream = getStrongRefVectorList( aafd, Node, Parent ); - if ( vectorStream == NULL ) { + if ( !vectorStream ) { error( "Could not retrieve StrongRefVectorList" ); goto err; } @@ -1748,20 +2027,21 @@ static int retrieveStrongReferenceVector( AAF_Data *aafd, aafProperty *Prop, aaf Node = getStrongRefEntryNode( aafd, Parent, refName, Entry._localKey ); - if ( Node == NULL ) { + if ( !Node ) { continue; } aafClass * Class = aafclass_getClassByID( aafd, (aafUID_t*)&Node->_clsId ); - if ( Class == NULL ) { - warning( "Could not retrieve Class ID %ls.", aaft_ClassIDToText( aafd, (aafUID_t*)&Node->_clsId ) ); + if ( !Class ) { + warning( "Could not retrieve Class ID %s.", + aaft_ClassIDToText( aafd, (aafUID_t*)&Node->_clsId ) ); continue; } aafObject * Obj = newObject( aafd, Node, Class, Parent ); - if ( Obj == NULL ) { + if ( !Obj ) { goto err; } @@ -1785,7 +2065,7 @@ static int retrieveStrongReferenceVector( AAF_Data *aafd, aafProperty *Prop, aaf aafObject *tmp = Prop->val; for (; tmp != NULL; tmp = tmp->next) - if ( tmp->next == NULL ) + if ( !tmp->next ) break; Obj->prev = tmp; @@ -1806,9 +2086,8 @@ static int retrieveStrongReferenceVector( AAF_Data *aafd, aafProperty *Prop, aaf rc = -1; end: - - if ( vectorStream ) - free( vectorStream ); + free( refName ); + free( vectorStream ); return rc; } @@ -1821,7 +2100,7 @@ static int retrieveProperty( AAF_Data *aafd, aafObject *Obj, aafPropertyDef *Def aafProperty *Prop = newProperty( aafd, Def ); - if ( Prop == NULL ) { + if ( !Prop ) { return -1; } @@ -1836,8 +2115,9 @@ static int retrieveProperty( AAF_Data *aafd, aafObject *Obj, aafPropertyDef *Def Prop->val = malloc( p->_length ); - if ( Prop->val == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !Prop->val ) { + error( "Out of memory" ); + free( Prop ); return -1; } @@ -1872,8 +2152,10 @@ static int retrieveObjectProperties( AAF_Data *aafd, aafObject *Obj ) aafByte_t *propStream = getNodeProperties( aafd, Obj->Node ); - if ( propStream == NULL ) { - error( "Could not retrieve object %ls properties : %ls", aaft_ClassIDToText(aafd, Obj->Class->ID), aaf_get_ObjectPath( Obj ) ); + if ( !propStream ) { + error( "Could not retrieve object %s properties : %s", + aaft_ClassIDToText(aafd, Obj->Class->ID), + aaf_get_ObjectPath( Obj ) ); goto err; } @@ -1885,7 +2167,7 @@ static int retrieveObjectProperties( AAF_Data *aafd, aafObject *Obj ) aafByte_t *value = NULL; aafPropertyDef *PDef = NULL; - int valueOffset = 0; + size_t valueOffset = 0; uint32_t i = 0; @@ -1894,15 +2176,20 @@ static int retrieveObjectProperties( AAF_Data *aafd, aafObject *Obj ) PDef = aafclass_getPropertyDefinitionByID( Obj->Class, Prop._pid ); - if ( PDef == NULL ) { - warning( "Unknown property 0x%04x (%ls) of object %ls", Prop._pid, aaft_PIDToText( aafd, Prop._pid ), aaft_ClassIDToText(aafd, Obj->Class->ID) ); + if ( !PDef ) { + warning( "Unknown property 0x%04x (%s) of object %s", + Prop._pid, + aaft_PIDToText( aafd, Prop._pid ), + aaft_ClassIDToText(aafd, Obj->Class->ID) ); continue; } rc = retrieveProperty( aafd, Obj, PDef, &Prop, value, Header._byteOrder ); if ( rc < 0 ) { - error( "Could not retrieve property %ls of object %ls", aaft_PIDToText( aafd, PDef->pid ), aaft_ClassIDToText(aafd, Obj->Class->ID) ); + error( "Could not retrieve property %s of object %s", + aaft_PIDToText( aafd, PDef->pid ), + aaft_ClassIDToText(aafd, Obj->Class->ID) ); goto err; } } @@ -1915,24 +2202,30 @@ static int retrieveObjectProperties( AAF_Data *aafd, aafObject *Obj ) end: - if ( propStream ) - free( propStream ); + free( propStream ); return rc; } -static cfbNode * getStrongRefIndexNode( AAF_Data *aafd, aafObject *Parent, const wchar_t *refName ) +static cfbNode * getStrongRefIndexNode( AAF_Data *aafd, aafObject *Parent, const char *refName ) { - wchar_t name[CFB_NODE_NAME_SZ]; + char name[CFB_NODE_NAME_SZ]; + + int rc = snprintf( name, CFB_NODE_NAME_SZ, "%s index", refName ); - swprintf( name, CFB_NODE_NAME_SZ, L"%" WPRIws L" index", refName ); + if ( rc < 0 || (size_t)rc >= CFB_NODE_NAME_SZ ) { + error( "snprintf() error" ); + return NULL; + } cfbNode * Node = cfb_getChildNode( aafd->cfbd, name, Parent->Node ); - if ( Node == NULL ) { - error( "Could not retrieve Reference Set/Vector Index Node @ \"%ls/%ls index\"", aaf_get_ObjectPath( Parent ), refName ); + if ( !Node ) { + error( "Could not retrieve Reference Set/Vector Index Node @ \"%s/%s index\"", + aaf_get_ObjectPath( Parent ), + refName ); return NULL; } @@ -1941,16 +2234,23 @@ static cfbNode * getStrongRefIndexNode( AAF_Data *aafd, aafObject *Parent, const -static cfbNode * getStrongRefEntryNode( AAF_Data *aafd, aafObject *Parent, const wchar_t *refName, uint16_t index ) +static cfbNode * getStrongRefEntryNode( AAF_Data *aafd, aafObject *Parent, const char *refName, uint32_t index ) { - wchar_t name[CFB_NODE_NAME_SZ]; + char name[CFB_NODE_NAME_SZ]; - swprintf( name, CFB_NODE_NAME_SZ, L"%" WPRIws L"{%x}", refName, index ); + int rc = snprintf( name, CFB_NODE_NAME_SZ, "%s{%x}", refName, index ); + + if ( rc < 0 || (size_t)rc >= CFB_NODE_NAME_SZ ) { + error( "snprintf() error" ); + return NULL; + } cfbNode *Node = cfb_getChildNode( aafd->cfbd, name, Parent->Node ); - if ( Node == NULL ) { - error( "Could not retrieve Reference Set/vector Entry Node @ \"%ls/%ls index\"", aaf_get_ObjectPath( Parent ), refName ); + if ( !Node ) { + error( "Could not retrieve Reference Set/vector Entry Node @ \"%s/%s index\"", + aaf_get_ObjectPath( Parent ), + refName ); return NULL; } @@ -1961,7 +2261,7 @@ static cfbNode * getStrongRefEntryNode( AAF_Data *aafd, aafObject *Parent, const static aafByte_t * getNodeProperties( AAF_Data *aafd, cfbNode *Node ) { - if ( Node == NULL ) { + if ( !Node ) { error( "Node is NULL" ); return NULL; } @@ -1970,9 +2270,9 @@ static aafByte_t * getNodeProperties( AAF_Data *aafd, cfbNode *Node ) aafByte_t *stream = NULL; - cfbNode *propNode = cfb_getChildNode( aafd->cfbd, L"properties", Node ); + cfbNode *propNode = cfb_getChildNode( aafd->cfbd, "properties", Node ); - if ( propNode == NULL ) { + if ( !propNode ) { error( "Could not retrieve Property Node" ); return NULL; } @@ -1980,7 +2280,7 @@ static aafByte_t * getNodeProperties( AAF_Data *aafd, cfbNode *Node ) cfb_getStream( aafd->cfbd, propNode, &stream, &stream_sz ); - if ( stream == NULL ) { + if ( !stream ) { error( "Could not retrieve Property Stream" ); return NULL; } @@ -2000,7 +2300,7 @@ static aafByte_t * getNodeProperties( AAF_Data *aafd, cfbNode *Node ) prop_sz += (((aafPropertyIndexEntry_t*)(stream+((sizeof(aafPropertyIndexEntry_t)*i)+sizeof(aafPropertyIndexHeader_t))))->_length) + sizeof(aafPropertyIndexEntry_t); if ( prop_sz != stream_sz ) - warning( "Stream length (%lu Bytes) does not match property length (%u Bytes).", + warning( L"Stream length (%lu Bytes) does not match property length (%u Bytes).", stream_sz, prop_sz ); */ @@ -2012,7 +2312,7 @@ static aafByte_t * getNodeProperties( AAF_Data *aafd, cfbNode *Node ) static aafStrongRefSetHeader_t * getStrongRefSetList( AAF_Data *aafd, cfbNode *Node, aafObject *Parent ) { - if ( Node == NULL ) + if ( !Node ) return NULL; aafByte_t *stream = NULL; @@ -2020,12 +2320,15 @@ static aafStrongRefSetHeader_t * getStrongRefSetList( AAF_Data *aafd, cfbNode *N cfb_getStream( aafd->cfbd, Node, &stream, &stream_sz ); - if ( stream == NULL ) { - wchar_t refName[CFB_NODE_NAME_SZ]; + if ( !stream ) { + + char *refName = cfb_w16toUTF8( Node->_ab, Node->_cb ); - cfb_w16towchar( refName, Node->_ab, Node->_cb ); + error( "Could not retrieve StrongReferenceSet Index Stream @ \"%s/%s index\"", + aaf_get_ObjectPath( Parent ), + refName ); - error( "Could not retrieve StrongReferenceSet Index Stream @ \"%ls/%ls index\"", aaf_get_ObjectPath( Parent ), refName ); + free( refName ); return NULL; } @@ -2037,7 +2340,7 @@ static aafStrongRefSetHeader_t * getStrongRefSetList( AAF_Data *aafd, cfbNode *N static aafByte_t * getStrongRefVectorList( AAF_Data *aafd, cfbNode *Node, aafObject *Parent ) { - if ( Node == NULL ) + if ( !Node ) return NULL; aafByte_t *stream = NULL; @@ -2045,12 +2348,14 @@ static aafByte_t * getStrongRefVectorList( AAF_Data *aafd, cfbNode *Node, aafObj cfb_getStream( aafd->cfbd, Node, &stream, &stream_sz ); - if ( stream == NULL ) { - wchar_t refName[CFB_NODE_NAME_SZ]; + if ( !stream ) { + + char *refName = cfb_w16toUTF8( Node->_ab, Node->_cb ); - cfb_w16towchar( refName, Node->_ab, Node->_cb ); + error( "Could not retrieve StrongReferenceVector Index Stream \"%s/%s index\"", + aaf_get_ObjectPath( Parent ), + refName ); - error( "Could not retrieve StrongReferenceVector Index Stream \"%ls/%ls index\"", aaf_get_ObjectPath( Parent ), refName ); return NULL; } diff --git a/src/AAFCore/AAFDump.c b/src/AAFCore/AAFDump.c index 17fade8..aa837cc 100644 --- a/src/AAFCore/AAFDump.c +++ b/src/AAFCore/AAFDump.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -24,69 +24,137 @@ #include #include #include +#include +#include +#include -#include "AAFClass.h" #include +#include "AAFClass.h" + -void aaf_dump_Header( AAF_Data *aafd ) +void aaf_dump_Header( AAF_Data *aafd, const char *padding ) { - struct dbg *dbg = aafd->dbg; + struct aafLog *log = aafd->log; - DBG_BUFFER_WRITE( dbg, " ByteOrder : %ls (0x%04x)\n", aaft_ByteOrderToText( aafd->Header.ByteOrder ), aafd->Header.ByteOrder ); - DBG_BUFFER_WRITE( dbg, " LastModified : %ls\n", aaft_TimestampToText( aafd->Header.LastModified ) ); - DBG_BUFFER_WRITE( dbg, " AAF ObjSpec Version : %ls\n", aaft_VersionToText( aafd->Header.Version ) ); - DBG_BUFFER_WRITE( dbg, " ObjectModel Version : %u\n", aafd->Header.ObjectModelVersion ); - DBG_BUFFER_WRITE( dbg, " Operational Pattern : %ls\n", aaft_OPDefToText( aafd->Header.OperationalPattern ) ); + LOG_BUFFER_WRITE( log, "%sByteOrder : %s%s (0x%04x)%s\n", padding, ANSI_COLOR_DARKGREY(log), aaft_ByteOrderToText( aafd->Header.ByteOrder ), aafd->Header.ByteOrder, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%sLastModified : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), aaft_TimestampToText( aafd->Header.LastModified ), ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%sAAF ObjSpec Version : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), aaft_VersionToText( aafd->Header.Version ), ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%sObjectModel Version : %s%u%s\n", padding, ANSI_COLOR_DARKGREY(log), aafd->Header.ObjectModelVersion, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%sOperational Pattern : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), aaft_OPDefToText( aafd->Header.OperationalPattern ), ANSI_COLOR_RESET(log) ); - DBG_BUFFER_WRITE( dbg, "\n\n" ); + LOG_BUFFER_WRITE( log, "\n\n" ); - dbg->debug_callback( dbg, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + log->debug_callback( log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); } -void aaf_dump_Identification( AAF_Data *aafd ) +void aaf_dump_Identification( AAF_Data *aafd, const char *padding ) { - struct dbg *dbg = aafd->dbg; + struct aafLog *log = aafd->log; - DBG_BUFFER_WRITE( dbg, " CompanyName : %ls\n", ( aafd->Identification.CompanyName ) ? aafd->Identification.CompanyName : L"n/a" ); - DBG_BUFFER_WRITE( dbg, " ProductName : %ls\n", ( aafd->Identification.ProductName ) ? aafd->Identification.ProductName : L"n/a" ); - DBG_BUFFER_WRITE( dbg, " ProductVersion : %ls\n", aaft_ProductVersionToText( aafd->Identification.ProductVersion ) ); - DBG_BUFFER_WRITE( dbg, " ProductVersionString : %ls\n", ( aafd->Identification.ProductVersionString ) ? aafd->Identification.ProductVersionString : L"n/a" ); - DBG_BUFFER_WRITE( dbg, " ProductID : %ls\n", AUIDToText( aafd->Identification.ProductID ) ); - DBG_BUFFER_WRITE( dbg, " Date : %ls\n", aaft_TimestampToText( aafd->Identification.Date ) ); - DBG_BUFFER_WRITE( dbg, " ToolkitVersion : %ls\n", aaft_ProductVersionToText( aafd->Identification.ToolkitVersion ) ); - DBG_BUFFER_WRITE( dbg, " Platform : %ls\n", ( aafd->Identification.Platform ) ? aafd->Identification.Platform : L"n/a" ); - DBG_BUFFER_WRITE( dbg, " GenerationAUID : %ls\n", AUIDToText( aafd->Identification.GenerationAUID ) ); + LOG_BUFFER_WRITE( log, "%sCompanyName : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), ( aafd->Identification.CompanyName ) ? aafd->Identification.CompanyName : "n/a", ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%sProductName : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), ( aafd->Identification.ProductName ) ? aafd->Identification.ProductName : "n/a", ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%sProductVersion : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), aaft_ProductVersionToText( aafd->Identification.ProductVersion ), ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%sProductVersionString : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), ( aafd->Identification.ProductVersionString ) ? aafd->Identification.ProductVersionString : "n/a", ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%sProductID : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), AUIDToText( aafd->Identification.ProductID ), ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%sDate : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), aaft_TimestampToText( aafd->Identification.Date ), ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%sToolkitVersion : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), aaft_ProductVersionToText( aafd->Identification.ToolkitVersion ), ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%sPlatform : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), ( aafd->Identification.Platform ) ? aafd->Identification.Platform : "n/a", ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%sGenerationAUID : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), AUIDToText( aafd->Identification.GenerationAUID ), ANSI_COLOR_RESET(log) ); - DBG_BUFFER_WRITE( dbg, "\n\n" ); + LOG_BUFFER_WRITE( log, "\n\n" ); - dbg->debug_callback( dbg, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + log->debug_callback( log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); } -void aaf_dump_ObjectProperty( AAF_Data *aafd, aafProperty *Prop ) +void aaf_dump_ObjectProperty( AAF_Data *aafd, aafProperty *Prop, const char *padding ) { - struct dbg *dbg = aafd->dbg; + struct aafLog *log = aafd->log; if ( Prop->def->meta ) { - DBG_BUFFER_WRITE( dbg, " :.: %s(0x%04x) %ls%s (%ls)\n", ANSI_COLOR_YELLOW(dbg), Prop->pid, aaft_PIDToText( aafd, Prop->pid ), ANSI_COLOR_RESET(dbg), aaft_StoredFormToText( Prop->sf ) /*AUIDToText( &Prop->def->type ),*/ /*aaft_TypeIDToText( &(Prop->def->type) )*/ ); - } else { - DBG_BUFFER_WRITE( dbg, " :.: (0x%04x) %ls (%ls)\n", Prop->pid, aaft_PIDToText( aafd, Prop->pid ), aaft_StoredFormToText( Prop->sf ) /*AUIDToText( &Prop->def->type ),*/ /*aaft_TypeIDToText( &(Prop->def->type) )*/ ); + LOG_BUFFER_WRITE( log, "%s%s[%s0x%04x%s] %s (%s)\n", + padding, + ANSI_COLOR_RESET(log), + ANSI_COLOR_MAGENTA(log), + Prop->pid, + ANSI_COLOR_RESET(log), + aaft_PIDToText( aafd, Prop->pid ), + aaft_StoredFormToText( Prop->sf ) ); + } + else { + LOG_BUFFER_WRITE( log, "%s%s[%s0x%04x%s] %s (%s)\n", + padding, + ANSI_COLOR_RESET(log), + ANSI_COLOR_DARKGREY(log), + Prop->pid, + ANSI_COLOR_RESET(log), + aaft_PIDToText( aafd, Prop->pid ), + aaft_StoredFormToText( Prop->sf ) ); } - // WARNING : Wont print strong references (set/vector) corectly. - aafd->dbg->_dbg_msg_pos += laaf_util_dump_hex( Prop->val, Prop->len, &aafd->dbg->_dbg_msg, &aafd->dbg->_dbg_msg_size, aafd->dbg->_dbg_msg_pos ); + int rc = laaf_util_dump_hex( Prop->val, Prop->len, &aafd->log->_msg, &aafd->log->_msg_size, aafd->log->_msg_pos, padding ); - dbg->debug_callback( dbg, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + if ( rc > 0 ) { + aafd->log->_msg_pos += (size_t)rc; + } + + log->debug_callback( log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); } -void aaf_dump_ObjectProperties( AAF_Data *aafd, aafObject *Obj ) +void aaf_dump_TaggedValueSet( AAF_Data *aafd, aafObject *ObjCollection, const char *padding ) +{ + struct aafLog *log = aafd->log; + + aafObject *Obj = NULL; + + int i = 0; + AAF_foreach_ObjectInSet( &Obj, ObjCollection, NULL ) { + + i++; + + if ( !aafUIDCmp( Obj->Class->ID, &AAFClassID_TaggedValue ) ) { + LOG_BUFFER_WRITE( log, "%s%sObject > %s\n", + padding, + ANSI_COLOR_RESET(log), + aaft_ClassIDToText( aafd, Obj->Class->ID ) ); + continue; + } + + char *name = aaf_get_propertyValue( Obj, PID_TaggedValue_Name, &AAFTypeID_String ); + aafIndirect_t *indirect = aaf_get_propertyValue( Obj, PID_TaggedValue_Value, &AAFTypeID_Indirect ); + + LOG_BUFFER_WRITE( log, "%s%sTagged > Name: %s%s%s%*s Value: %s(%s)%s %s%s%s%s%s\n", + padding, + ANSI_COLOR_RESET(log), + ANSI_COLOR_DARKGREY(log), + (name) ? name : "", + ANSI_COLOR_RESET(log), + (name) ? (size_t)(34-(int)strlen(name)) : (size_t)(34-strlen("")), " ", + ANSI_COLOR_DARKGREY(log), + aaft_TypeIDToText( &indirect->TypeDef ), + ANSI_COLOR_RESET(log), + ANSI_COLOR_DARKGREY(log), + ( aafUIDCmp( &indirect->TypeDef, &AAFTypeID_String ) ) ? "\"" : "", + aaft_IndirectValueToText( aafd, indirect ), + ( aafUIDCmp( &indirect->TypeDef, &AAFTypeID_String ) ) ? "\"" : "", + ANSI_COLOR_RESET(log) ); + + log->debug_callback( log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); + + free( name ); + } +} + + + +void aaf_dump_ObjectProperties( AAF_Data *aafd, aafObject *Obj, const char *padding ) { /* * List the properties once they have been parsed and interpreted by AAFCore. @@ -95,21 +163,24 @@ void aaf_dump_ObjectProperties( AAF_Data *aafd, aafObject *Obj ) aafProperty * Prop = NULL; for ( Prop = Obj->Properties; Prop != NULL; Prop = Prop->next ) { - aaf_dump_ObjectProperty( aafd, Prop ); + aaf_dump_ObjectProperty( aafd, Prop, padding ); } } -void aaf_dump_rawProperties( AAF_Data *aafd, aafByte_t *propStream ) +void aaf_dump_rawProperties( AAF_Data *aafd, aafByte_t *propStream, const char *padding ) { - struct dbg *dbg = aafd->dbg; + struct aafLog *log = aafd->log; if ( propStream == NULL ) { - DBG_BUFFER_WRITE( dbg, - " ## Property_Header____________________________________________________\n\n" - " aafPropertyIndexHeader_t is NULL\n" - " ======================================================================\n\n" + LOG_BUFFER_WRITE( log, + "%s## Property_Header____________________________________________________\n\n" + "%saafPropertyIndexHeader_t is NULL\n" + "%s======================================================================\n\n", + padding, + padding, + padding ); return; } @@ -121,59 +192,55 @@ void aaf_dump_rawProperties( AAF_Data *aafd, aafByte_t *propStream ) memcpy( &Header, propStream, sizeof(aafPropertyIndexHeader_t) ); uint32_t i = 0; - uint32_t valueOffset = 0; - - - DBG_BUFFER_WRITE( dbg, - " ## Property_Header____________________________________________________\n\n" - " _byteOrder : 0x%02x\n" - " _formatVersion : 0x%02x\n" - " _entryCount : %u\n\n" - " ======================================================================\n\n", - Header._byteOrder, - Header._formatVersion, - Header._entryCount + size_t valueOffset = 0; + + + LOG_BUFFER_WRITE( log, + "%s## Property_Header____________________________________________________\n\n" + "%s_byteOrder : %s0x%02x%s\n" + "%s_formatVersion : %s0x%02x%s\n" + "%s_entryCount : %s%u%s\n\n" + "%s======================================================================\n\n", + padding, + padding, ANSI_COLOR_DARKGREY(log), Header._byteOrder, ANSI_COLOR_RESET(log), + padding, ANSI_COLOR_DARKGREY(log), Header._formatVersion, ANSI_COLOR_RESET(log), + padding, ANSI_COLOR_DARKGREY(log), Header._entryCount, ANSI_COLOR_RESET(log), + padding ); - DBG_BUFFER_WRITE( dbg, "\n\n" ); + LOG_BUFFER_WRITE( log, "\n\n" ); /* * Since the following for-loop macro is not intended to be user * accessible, it has been defined as a local macro in AAFCore.c. */ - - // foreachPropertyEntry( Header, Prop, value, i ) - for ( valueOffset = sizeof(aafPropertyIndexHeader_t) + (Header._entryCount * sizeof(aafPropertyIndexEntry_t)), \ - i = 0; \ - i < Header._entryCount && \ - memcpy( &Prop, (propStream + ((sizeof(aafPropertyIndexHeader_t)) + (sizeof(aafPropertyIndexEntry_t) * i))), sizeof(aafPropertyIndexEntry_t) ) && \ - (value = propStream + valueOffset); \ - valueOffset += Prop._length, \ - i++ ) - { - - DBG_BUFFER_WRITE( dbg, - " #%u Property_Entry_____________________________________________________\n" - " _pid : 0x%04x (%ls)\n" - " _storedForm : %ls\n" - " _length : %u bytes\n", - i, - Prop._pid, aaft_PIDToText( aafd, Prop._pid ), - aaft_StoredFormToText( Prop._storedForm ), - Prop._length + foreachPropertyEntry( propStream, Header, Prop, value, valueOffset, i ) { + LOG_BUFFER_WRITE( log, + "%s#%u Property_Entry_____________________________________________________\n" + "%s_pid : %s0x%04x (%s)%s\n" + "%s_storedForm : %s%s%s\n" + "%s_length : %s%u bytes%s\n", + padding, i, + padding, ANSI_COLOR_DARKGREY(log), Prop._pid, aaft_PIDToText( aafd, Prop._pid ), ANSI_COLOR_RESET(log), + padding, ANSI_COLOR_DARKGREY(log), aaft_StoredFormToText( Prop._storedForm ), ANSI_COLOR_RESET(log), + padding, ANSI_COLOR_DARKGREY(log), Prop._length, ANSI_COLOR_RESET(log) ); - aafd->dbg->_dbg_msg_pos += laaf_util_dump_hex( value, Prop._length, &aafd->dbg->_dbg_msg, &aafd->dbg->_dbg_msg_size, aafd->dbg->_dbg_msg_pos ); + int rc = laaf_util_dump_hex( value, Prop._length, &aafd->log->_msg, &aafd->log->_msg_size, aafd->log->_msg_pos, padding ); + + if ( rc > 0 ) { + aafd->log->_msg_pos += (size_t)rc; + } - DBG_BUFFER_WRITE( dbg, "\n" ); + LOG_BUFFER_WRITE( log, "\n" ); } - dbg->debug_callback( dbg, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + log->debug_callback( log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); } -void aaf_dump_nodeStreamProperties( AAF_Data *aafd, cfbNode *node ) +void aaf_dump_nodeStreamProperties( AAF_Data *aafd, cfbNode *node, const char *padding ) { /* * List the raw properties directly from a CFB Node's stream. @@ -183,14 +250,14 @@ void aaf_dump_nodeStreamProperties( AAF_Data *aafd, cfbNode *node ) cfb_getStream( aafd->cfbd, node, &propStream, NULL ); - aaf_dump_rawProperties( aafd, propStream ); + aaf_dump_rawProperties( aafd, propStream, padding ); free( propStream ); } -void aaf_dump_MetaDictionary( AAF_Data *aafd ) +void aaf_dump_MetaDictionary( AAF_Data *aafd, const char *padding ) { /* * NOTE Only dumps the "custom" classes/properties, since those are the only @@ -198,7 +265,7 @@ void aaf_dump_MetaDictionary( AAF_Data *aafd ) * wont be printed out. */ - struct dbg *dbg = aafd->dbg; + struct aafLog *log = aafd->log; aafClass *Class = NULL; @@ -213,44 +280,44 @@ void aaf_dump_MetaDictionary( AAF_Data *aafd ) foreachPropertyDefinition( PDef, Class->Properties ) { if ( Class->meta ) { - DBG_BUFFER_WRITE( dbg, "%s%ls::%ls (0x%04x)%s\n", - ANSI_COLOR_YELLOW(dbg), + LOG_BUFFER_WRITE( log, "%s%s%s::%s (0x%04x)%s\n", + padding, + ANSI_COLOR_MAGENTA(log), Class->name, PDef->name, PDef->pid, - ANSI_COLOR_RESET(dbg) ); + ANSI_COLOR_RESET(log) ); print++; } else if ( PDef->meta ) { - DBG_BUFFER_WRITE( dbg, "%ls::%s%ls (0x%04x)%s\n", + LOG_BUFFER_WRITE( log, "%s%s::%s%s (0x%04x)%s\n", + padding, aaft_ClassIDToText( aafd, Class->ID ), - ANSI_COLOR_YELLOW(dbg), + ANSI_COLOR_MAGENTA(log), PDef->name, PDef->pid, - ANSI_COLOR_RESET(dbg) ); + ANSI_COLOR_RESET(log) ); print++; } } if ( print ) { - DBG_BUFFER_WRITE( dbg, "\n" ); + LOG_BUFFER_WRITE( log, "\n" ); } - - print = 1; } - DBG_BUFFER_WRITE( dbg, "\n\n" ); + LOG_BUFFER_WRITE( log, "\n\n" ); - dbg->debug_callback( dbg, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + log->debug_callback( log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); } -void aaf_dump_Classes( AAF_Data *aafd ) +void aaf_dump_Classes( AAF_Data *aafd, const char *padding ) { - struct dbg *dbg = aafd->dbg; + struct aafLog *log = aafd->log; aafClass *ConcreteClass = NULL; aafClass *Class = NULL; @@ -259,21 +326,23 @@ void aaf_dump_Classes( AAF_Data *aafd ) { foreachClassInheritance( Class, ConcreteClass ) { - DBG_BUFFER_WRITE( dbg, "%s%ls%s", - (Class->meta) ? ANSI_COLOR_YELLOW(dbg) : "", + LOG_BUFFER_WRITE( log, "%s%s%s%s", + padding, + (Class->meta) ? ANSI_COLOR_MAGENTA(log) : "", aaft_ClassIDToText( aafd, Class->ID ), - (Class->meta) ? ANSI_COLOR_RESET(dbg) : "" ); + (Class->meta) ? ANSI_COLOR_RESET(log) : "" ); - if ( Class->Parent != NULL ) - DBG_BUFFER_WRITE( dbg, " > " ); + if ( Class->Parent != NULL ) { + LOG_BUFFER_WRITE( log, " > " ); + } } - DBG_BUFFER_WRITE( dbg, "\n" ); + LOG_BUFFER_WRITE( log, "\n" ); } - DBG_BUFFER_WRITE( dbg, "\n\n" ); + LOG_BUFFER_WRITE( log, "\n\n" ); - dbg->debug_callback( dbg, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + log->debug_callback( log, (void*)aafd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); } diff --git a/src/AAFCore/AAFToText.c b/src/AAFCore/AAFToText.c index 95c0b94..2080d14 100644 --- a/src/AAFCore/AAFToText.c +++ b/src/AAFCore/AAFToText.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -19,7 +19,8 @@ */ #include -#include +#include +#include #include #include @@ -37,29 +38,78 @@ #include #include -#include "AAFClass.h" #include +#include "AAFClass.h" + + + +#define debug( ... ) \ + AAF_LOG( aafd->log, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_DEBUG, __VA_ARGS__ ) + +#define warning( ... ) \ + AAF_LOG( aafd->log, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_WARNING, __VA_ARGS__ ) +#define error( ... ) \ + AAF_LOG( aafd->log, aafd, DEBUG_SRC_ID_AAF_CORE, VERB_ERROR, __VA_ARGS__ ) -const wchar_t * aaft_MobIDToText( aafMobID_t *mobid ) + +const char * aaft_MobIDToText( aafMobID_t *mobid ) { - static wchar_t str[127]; + size_t strsz = 200; + static char str[200]; - uint32_t i = 0; + size_t i = 0; uint32_t offset = 0; + int rc = 0; for ( i = 0; i < sizeof(aafMobID_t); i++ ) { - if ( i == 12 ) offset += swprintf( str+offset, (2 * sizeof(aafMobID_t)), L" - " ); - if ( i == 13 ) offset += swprintf( str+offset, (2 * sizeof(aafMobID_t)), L" - " ); - if ( i == 14 ) offset += swprintf( str+offset, (2 * sizeof(aafMobID_t)), L" - " ); - if ( i == 15 ) offset += swprintf( str+offset, (2 * sizeof(aafMobID_t)), L" - " ); + switch ( i ) { + case 12: + case 13: + case 14: + case 15: + rc = snprintf( str+offset, strsz-offset, " - " ); + + assert( rc > 0 && (size_t)rc < strsz-offset ); + // if ( rc < 0 || (size_t)rc >= strsz-offset ) { + // fprintf( stderr, "snprintf() error" ); + // return NULL; + // } + + offset += (uint32_t)rc; + + break; + + default: + break; + } + + rc = snprintf( str+offset, strsz-offset, "%02x", ((unsigned char*)mobid)[i] ); + + assert( rc > 0 && (size_t)rc < strsz-offset ); + + // if ( rc < 0 || (size_t)rc >= strsz-offset ) { + // fprintf( stderr, "snprintf() error" ); + // return "NULL"; + // } + + offset += (uint32_t)rc; - offset += swprintf( str+offset, 127, L"%02x", ((unsigned char*)mobid)[i] ); if ( i == 15 ) { - offset += swprintf( str+offset, 127, L" - " ); + rc = snprintf( str+offset, strsz-offset, " - " ); + + assert( rc > 0 && (size_t)rc < strsz-offset ); + + // if ( rc < 0 || (size_t)rc >= strsz-offset ) { + // fprintf( stderr, "snprintf() error" ); + // return "NULL"; + // } + + offset += (uint32_t)rc; + break; } } @@ -68,16 +118,23 @@ const wchar_t * aaft_MobIDToText( aafMobID_t *mobid ) memcpy( &material, ((unsigned char*)mobid)+i, sizeof(aafUID_t) ); - offset += swprintf( str+offset, 127, L"%" WPRIws, AUIDToText(&material) ); + rc = snprintf( str+offset, strsz-offset, "%s", AUIDToText(&material) ); + + assert( rc >= 0 && (size_t)rc < strsz-offset ); + + // if ( rc < 0 || (size_t)rc >= strsz-offset ) { + // fprintf( stderr, "snprintf() error" ); + // return "NULL"; + // } return str; } -const wchar_t * aaft_TimestampToText( aafTimeStamp_t *ts ) +const char * aaft_TimestampToText( aafTimeStamp_t *ts ) { - static wchar_t str[24]; + static char str[32]; if ( ts == NULL ) { str[0] = 'n'; @@ -86,7 +143,7 @@ const wchar_t * aaft_TimestampToText( aafTimeStamp_t *ts ) str[3] = '\0'; } else { - swprintf( str, sizeof(str), L"%04i-%02u-%02u %02u:%02u:%02u.%02u", + int rc = snprintf( str, sizeof(str), "%04i-%02u-%02u %02u:%02u:%02u.%02u", ts->date.year, ts->date.month, ts->date.day, @@ -94,6 +151,13 @@ const wchar_t * aaft_TimestampToText( aafTimeStamp_t *ts ) ts->time.minute, ts->time.second, ts->time.fraction ); + + assert( rc > 0 && (size_t)rc < sizeof(str) ); + + // if ( rc < 0 || (size_t)rc >= sizeof(str) ) { + // fprintf( stderr, "snprintf() error" ); + // return "NULL"; + // } } return str; @@ -101,9 +165,9 @@ const wchar_t * aaft_TimestampToText( aafTimeStamp_t *ts ) -const wchar_t * aaft_VersionToText( aafVersionType_t *vers ) +const char * aaft_VersionToText( aafVersionType_t *vers ) { - static wchar_t str[16]; + static char str[16]; if ( vers == NULL ) { str[0] = 'n'; @@ -112,9 +176,16 @@ const wchar_t * aaft_VersionToText( aafVersionType_t *vers ) str[3] = '\0'; } else { - swprintf( str, sizeof(str), L"%i.%i", + int rc = snprintf( str, sizeof(str), "%i.%i", vers->major, vers->minor ); + + assert( rc > 0 && (size_t)rc < sizeof(str) ); + + // if ( rc < 0 || (size_t)rc >= sizeof(str) ) { + // fprintf( stderr, "snprintf() error" ); + // return "NULL"; + // } } return str; @@ -122,9 +193,9 @@ const wchar_t * aaft_VersionToText( aafVersionType_t *vers ) -const wchar_t * aaft_ProductVersionToText( aafProductVersion_t *vers ) +const char * aaft_ProductVersionToText( aafProductVersion_t *vers ) { - static wchar_t str[64]; + static char str[64]; if ( vers == NULL ) { str[0] = 'n'; @@ -133,13 +204,20 @@ const wchar_t * aaft_ProductVersionToText( aafProductVersion_t *vers ) str[3] = '\0'; } else { - swprintf( str, sizeof(str), L"%u.%u.%u.%u %" WPRIws L" (%i)", + int rc = snprintf( str, sizeof(str), "%u.%u.%u.%u %s (%i)", vers->major, vers->minor, vers->tertiary, vers->patchLevel, aaft_ProductReleaseTypeToText( vers->type ), vers->type ); + + assert( rc > 0 && (size_t)rc < sizeof(str) ); + + // if ( rc < 0 || (size_t)rc >= sizeof(str) ) { + // fprintf( stderr, "snprintf() error" ); + // return "NULL"; + // } } return str; @@ -147,524 +225,539 @@ const wchar_t * aaft_ProductVersionToText( aafProductVersion_t *vers ) -const wchar_t * aaft_FileKindToText( const aafUID_t *auid ) +const char * aaft_FileKindToText( const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; + return "n/a"; /* NOTE: AAFUID_NULL = AAFFileKind_DontCare */ - if ( aafUIDCmp( auid, &AAFFileKind_DontCare ) ) return L"AAFFileKind_DontCare"; - if ( aafUIDCmp( auid, &AAFFileKind_Aaf512Binary ) ) return L"AAFFileKind_Aaf512Binary"; - if ( aafUIDCmp( auid, &AAFFileKind_Aaf4KBinary ) ) return L"AAFFileKind_Aaf4KBinary"; - if ( aafUIDCmp( auid, &AAFFileKind_AafXmlText ) ) return L"AAFFileKind_AafXmlText"; - if ( aafUIDCmp( auid, &AAFFileKind_AafKlvBinary ) ) return L"AAFFileKind_AafKlvBinary"; - if ( aafUIDCmp( auid, &AAFFileKind_AafM512Binary ) ) return L"AAFFileKind_AafM512Binary"; - if ( aafUIDCmp( auid, &AAFFileKind_AafS512Binary ) ) return L"AAFFileKind_AafS512Binary"; - if ( aafUIDCmp( auid, &AAFFileKind_AafG512Binary ) ) return L"AAFFileKind_AafG512Binary"; - if ( aafUIDCmp( auid, &AAFFileKind_AafM4KBinary ) ) return L"AAFFileKind_AafM4KBinary"; - if ( aafUIDCmp( auid, &AAFFileKind_AafS4KBinary ) ) return L"AAFFileKind_AafS4KBinary"; - if ( aafUIDCmp( auid, &AAFFileKind_AafG4KBinary ) ) return L"AAFFileKind_AafG4KBinary"; - if ( aafUIDCmp( auid, &AAFFileKind_Pathological ) ) return L"AAFFileKind_Pathological"; - - return L"Unknown AAFFileKind"; + if ( aafUIDCmp( auid, &AAFFileKind_DontCare ) ) return "AAFFileKind_DontCare"; + if ( aafUIDCmp( auid, &AAFFileKind_Aaf512Binary ) ) return "AAFFileKind_Aaf512Binary"; + if ( aafUIDCmp( auid, &AAFFileKind_Aaf4KBinary ) ) return "AAFFileKind_Aaf4KBinary"; + if ( aafUIDCmp( auid, &AAFFileKind_AafXmlText ) ) return "AAFFileKind_AafXmlText"; + if ( aafUIDCmp( auid, &AAFFileKind_AafKlvBinary ) ) return "AAFFileKind_AafKlvBinary"; + if ( aafUIDCmp( auid, &AAFFileKind_AafM512Binary ) ) return "AAFFileKind_AafM512Binary"; + if ( aafUIDCmp( auid, &AAFFileKind_AafS512Binary ) ) return "AAFFileKind_AafS512Binary"; + if ( aafUIDCmp( auid, &AAFFileKind_AafG512Binary ) ) return "AAFFileKind_AafG512Binary"; + if ( aafUIDCmp( auid, &AAFFileKind_AafM4KBinary ) ) return "AAFFileKind_AafM4KBinary"; + if ( aafUIDCmp( auid, &AAFFileKind_AafS4KBinary ) ) return "AAFFileKind_AafS4KBinary"; + if ( aafUIDCmp( auid, &AAFFileKind_AafG4KBinary ) ) return "AAFFileKind_AafG4KBinary"; + if ( aafUIDCmp( auid, &AAFFileKind_Pathological ) ) return "AAFFileKind_Pathological"; + + return "Unknown AAFFileKind"; } -const wchar_t * aaft_TapeCaseTypeToText( aafTapeCaseType_t t ) +const char * aaft_TapeCaseTypeToText( aafTapeCaseType_t t ) { switch ( t ) { - case AAFTapeCaseNull: return L"AAFTapeCaseNull"; - case AAFThreeFourthInchVideoTape: return L"AAFThreeFourthInchVideoTape"; - case AAFVHSVideoTape: return L"AAFVHSVideoTape"; - case AAF8mmVideoTape: return L"AAF8mmVideoTape"; - case AAFBetacamVideoTape: return L"AAFBetacamVideoTape"; - case AAFCompactCassette: return L"AAFCompactCassette"; - case AAFDATCartridge: return L"AAFDATCartridge"; - case AAFNagraAudioTape: return L"AAFNagraAudioTape"; + case AAFTapeCaseNull: return "AAFTapeCaseNull"; + case AAFThreeFourthInchVideoTape: return "AAFThreeFourthInchVideoTape"; + case AAFVHSVideoTape: return "AAFVHSVideoTape"; + case AAF8mmVideoTape: return "AAF8mmVideoTape"; + case AAFBetacamVideoTape: return "AAFBetacamVideoTape"; + case AAFCompactCassette: return "AAFCompactCassette"; + case AAFDATCartridge: return "AAFDATCartridge"; + case AAFNagraAudioTape: return "AAFNagraAudioTape"; } - return L"Unknown TapeCaseType"; + return "Unknown TapeCaseType"; } -const wchar_t * aaft_VideoSignalTypeToText( aafVideoSignalType_t v ) +const char * aaft_VideoSignalTypeToText( aafVideoSignalType_t v ) { switch ( v ) { - case AAFVideoSignalNull: return L"AAFVideoSignalNull"; - case AAFNTSCSignal: return L"AAFNTSCSignal"; - case AAFPALSignal: return L"AAFPALSignal"; - case AAFSECAMSignal: return L"AAFSECAMSignal"; + case AAFVideoSignalNull: return "AAFVideoSignalNull"; + case AAFNTSCSignal: return "AAFNTSCSignal"; + case AAFPALSignal: return "AAFPALSignal"; + case AAFSECAMSignal: return "AAFSECAMSignal"; } - return L"Unknown VideoSignalType"; + return "Unknown VideoSignalType"; } -const wchar_t * aaft_TapeFormatTypeToText( aafTapeFormatType_t t ) +const char * aaft_TapeFormatTypeToText( aafTapeFormatType_t t ) { switch ( t ) { - case AAFTapeFormatNull: return L"AAFTapeFormatNull"; - case AAFBetacamFormat: return L"AAFBetacamFormat"; - case AAFBetacamSPFormat: return L"AAFBetacamSPFormat"; - case AAFVHSFormat: return L"AAFVHSFormat"; - case AAFSVHSFormat: return L"AAFSVHSFormat"; - case AAF8mmFormat: return L"AAF8mmFormat"; - case AAFHi8Format: return L"AAFHi8Format"; + case AAFTapeFormatNull: return "AAFTapeFormatNull"; + case AAFBetacamFormat: return "AAFBetacamFormat"; + case AAFBetacamSPFormat: return "AAFBetacamSPFormat"; + case AAFVHSFormat: return "AAFVHSFormat"; + case AAFSVHSFormat: return "AAFSVHSFormat"; + case AAF8mmFormat: return "AAF8mmFormat"; + case AAFHi8Format: return "AAFHi8Format"; } - return L"Unknown TapeFormatType"; + return "Unknown TapeFormatType"; } -const wchar_t * aaft_FilmTypeToText( aafFilmType_t f ) +const char * aaft_FilmTypeToText( aafFilmType_t f ) { switch ( f ) { - case AAFFtNull: return L"AAFFtNull"; - case AAFFt35MM: return L"AAFFt35MM"; - case AAFFt16MM: return L"AAFFt16MM"; - case AAFFt8MM: return L"AAFFt8MM"; - case AAFFt65MM: return L"AAFFt65MM"; + case AAFFtNull: return "AAFFtNull"; + case AAFFt35MM: return "AAFFt35MM"; + case AAFFt16MM: return "AAFFt16MM"; + case AAFFt8MM: return "AAFFt8MM"; + case AAFFt65MM: return "AAFFt65MM"; } - return L"Unknown FilmType"; + return "Unknown FilmType"; } -const wchar_t * aaft_SignalStandardToText( aafSignalStandard_t s ) +const char * aaft_SignalStandardToText( aafSignalStandard_t s ) { switch ( s ) { - case AAFSignalStandard_None: return L"AAFSignalStandard_None"; - case AAFSignalStandard_ITU601: return L"AAFSignalStandard_ITU601"; - case AAFSignalStandard_ITU1358: return L"AAFSignalStandard_ITU1358"; - case AAFSignalStandard_SMPTE347M: return L"AAFSignalStandard_SMPTE347M"; - case AAFSignalStandard_SMPTE274M: return L"AAFSignalStandard_SMPTE274M"; - case AAFSignalStandard_SMPTE296M: return L"AAFSignalStandard_SMPTE296M"; - case AAFSignalStandard_SMPTE349M: return L"AAFSignalStandard_SMPTE349M"; + case AAFSignalStandard_None: return "AAFSignalStandard_None"; + case AAFSignalStandard_ITU601: return "AAFSignalStandard_ITU601"; + case AAFSignalStandard_ITU1358: return "AAFSignalStandard_ITU1358"; + case AAFSignalStandard_SMPTE347M: return "AAFSignalStandard_SMPTE347M"; + case AAFSignalStandard_SMPTE274M: return "AAFSignalStandard_SMPTE274M"; + case AAFSignalStandard_SMPTE296M: return "AAFSignalStandard_SMPTE296M"; + case AAFSignalStandard_SMPTE349M: return "AAFSignalStandard_SMPTE349M"; } - return L"Unknown SignalStandard"; + return "Unknown SignalStandard"; } -const wchar_t * aaft_FieldNumberToText( aafFieldNumber_t f ) +const char * aaft_FieldNumberToText( aafFieldNumber_t f ) { switch ( f ) { - case AAFUnspecifiedField: return L"AAFUnspecifiedField"; - case AAFFieldOne: return L"AAFFieldOne"; - case AAFFieldTwo: return L"AAFFieldTwo"; + case AAFUnspecifiedField: return "AAFUnspecifiedField"; + case AAFFieldOne: return "AAFFieldOne"; + case AAFFieldTwo: return "AAFFieldTwo"; } - return L"Unknown FieldNumber"; + return "Unknown FieldNumber"; } -const wchar_t * aaft_AlphaTransparencyToText( aafAlphaTransparency_t a ) +const char * aaft_AlphaTransparencyToText( aafAlphaTransparency_t a ) { switch ( a ) { - case AAFMinValueTransparent: return L"AAFMinValueTransparent"; - case AAFMaxValueTransparent: return L"AAFMaxValueTransparent"; + case AAFMinValueTransparent: return "AAFMinValueTransparent"; + case AAFMaxValueTransparent: return "AAFMaxValueTransparent"; } - return L"Unknown AlphaTransparency"; + return "Unknown AlphaTransparency"; } -const wchar_t * aaft_FrameLayoutToText( aafFrameLayout_t f ) +const char * aaft_FrameLayoutToText( aafFrameLayout_t f ) { switch ( f ) { - case AAFFullFrame: return L"AAFFullFrame"; - case AAFSeparateFields: return L"AAFSeparateFields"; - case AAFOneField: return L"AAFOneField"; - case AAFMixedFields: return L"AAFMixedFields"; - case AAFSegmentedFrame: return L"AAFSegmentedFrame"; + case AAFFullFrame: return "AAFFullFrame"; + case AAFSeparateFields: return "AAFSeparateFields"; + case AAFOneField: return "AAFOneField"; + case AAFMixedFields: return "AAFMixedFields"; + case AAFSegmentedFrame: return "AAFSegmentedFrame"; } - return L"Unknown FrameLayout"; + return "Unknown FrameLayout"; } -const wchar_t * aaft_ColorSitingToText( aafColorSiting_t c ) +const char * aaft_ColorSitingToText( aafColorSiting_t c ) { switch ( c ) { - case AAFCoSiting: return L"AAFCoSiting"; - case AAFAveraging: return L"AAFAveraging"; - case AAFThreeTap: return L"AAFThreeTap"; - case AAFQuincunx: return L"AAFQuincunx"; - case AAFRec601: return L"AAFRec601"; - case AAFUnknownSiting: return L"AAFUnknownSiting"; + case AAFCoSiting: return "AAFCoSiting"; + case AAFAveraging: return "AAFAveraging"; + case AAFThreeTap: return "AAFThreeTap"; + case AAFQuincunx: return "AAFQuincunx"; + case AAFRec601: return "AAFRec601"; + case AAFUnknownSiting: return "AAFUnknownSiting"; } - return L"Unknown ColorSiting"; + return "Unknown ColorSiting"; } -const wchar_t * aaft_ProductReleaseTypeToText( aafProductReleaseType_t t ) +const char * aaft_ProductReleaseTypeToText( aafProductReleaseType_t t ) { switch ( t ) { - case AAFVersionUnknown: return L"AAFVersionUnknown"; - case AAFVersionReleased: return L"AAFVersionReleased"; - case AAFVersionDebug: return L"AAFVersionDebug"; - case AAFVersionPatched: return L"AAFVersionPatched"; - case AAFVersionBeta: return L"AAFVersionBeta"; - case AAFVersionPrivateBuild: return L"AAFVersionPrivateBuild"; + case AAFVersionUnknown: return "AAFVersionUnknown"; + case AAFVersionReleased: return "AAFVersionReleased"; + case AAFVersionDebug: return "AAFVersionDebug"; + case AAFVersionPatched: return "AAFVersionPatched"; + case AAFVersionBeta: return "AAFVersionBeta"; + case AAFVersionPrivateBuild: return "AAFVersionPrivateBuild"; } - return L"Unknown ProductReleaseType"; + return "Unknown ProductReleaseType"; } -const wchar_t * aaft_FadeTypeToText( aafFadeType_t f ) +const char * aaft_FadeTypeToText( aafFadeType_t f ) { switch ( f ) { - case AAFFadeNone: return L"AAFFadeNone"; - case AAFFadeLinearAmp: return L"AAFFadeLinearAmp"; - case AAFFadeLinearPower: return L"AAFFadeLinearPower"; + case AAFFadeNone: return "AAFFadeNone"; + case AAFFadeLinearAmp: return "AAFFadeLinearAmp"; + case AAFFadeLinearPower: return "AAFFadeLinearPower"; } - return L"Unknown FadeType"; + return "Unknown FadeType"; } -const wchar_t * aaft_BoolToText( aafBoolean_t b ) +const char * aaft_BoolToText( aafBoolean_t b ) { switch ( b ) { - case 1: return L"True"; - case 0: return L"False"; + case 1: return "True"; + case 0: return "False"; } - return L"Unknown Boolean"; + return "Unknown Boolean"; } -const wchar_t * aaft_OperationCategoryToText( const aafUID_t *auid ) +const char * aaft_OperationCategoryToText( const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; + return "n/a"; - if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return L"AAFUID_NULL"; - if ( aafUIDCmp( auid, &AAFOperationCategory_Effect ) ) return L"AAFOperationCategory_Effect"; + if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return "AAFUID_NULL"; + if ( aafUIDCmp( auid, &AAFOperationCategory_Effect ) ) return "AAFOperationCategory_Effect"; - return L"Unknown AAFOperationCategory"; + return "Unknown AAFOperationCategory"; } -const wchar_t * aaft_PluginCategoryToText( const aafUID_t *auid ) +const char * aaft_PluginCategoryToText( const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; + return "n/a"; - if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return L"AAFUID_NULL"; - if ( aafUIDCmp( auid, &AAFPluginCategory_Effect ) ) return L"AAFPluginCategory_Effect"; - if ( aafUIDCmp( auid, &AAFPluginCategory_Codec ) ) return L"AAFPluginCategory_Codec"; - if ( aafUIDCmp( auid, &AAFPluginCategory_Interpolation ) ) return L"AAFPluginCategory_Interpolation"; + if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return "AAFUID_NULL"; + if ( aafUIDCmp( auid, &AAFPluginCategory_Effect ) ) return "AAFPluginCategory_Effect"; + if ( aafUIDCmp( auid, &AAFPluginCategory_Codec ) ) return "AAFPluginCategory_Codec"; + if ( aafUIDCmp( auid, &AAFPluginCategory_Interpolation ) ) return "AAFPluginCategory_Interpolation"; - return L"Unknown AAFPluginCategory"; + return "Unknown AAFPluginCategory"; } -const wchar_t * aaft_ScanningDirectionToText( aafScanningDirection_t s ) +const char * aaft_ScanningDirectionToText( aafScanningDirection_t s ) { switch ( s ) { - case AAFScanningDirection_LeftToRightTopToBottom: return L"AAFScanningDirection_LeftToRightTopToBottom"; - case AAFScanningDirection_RightToLeftTopToBottom: return L"AAFScanningDirection_RightToLeftTopToBottom"; - case AAFScanningDirection_LeftToRightBottomToTop: return L"AAFScanningDirection_LeftToRightBottomToTop"; - case AAFScanningDirection_RightToLeftBottomToTop: return L"AAFScanningDirection_RightToLeftBottomToTop"; - case AAFScanningDirection_TopToBottomLeftToRight: return L"AAFScanningDirection_TopToBottomLeftToRight"; - case AAFScanningDirection_TopToBottomRightToLeft: return L"AAFScanningDirection_TopToBottomRightToLeft"; - case AAFScanningDirection_BottomToTopLeftToRight: return L"AAFScanningDirection_BottomToTopLeftToRight"; - case AAFScanningDirection_BottomToTopRightToLeft: return L"AAFScanningDirection_BottomToTopRightToLeft"; + case AAFScanningDirection_LeftToRightTopToBottom: return "AAFScanningDirection_LeftToRightTopToBottom"; + case AAFScanningDirection_RightToLeftTopToBottom: return "AAFScanningDirection_RightToLeftTopToBottom"; + case AAFScanningDirection_LeftToRightBottomToTop: return "AAFScanningDirection_LeftToRightBottomToTop"; + case AAFScanningDirection_RightToLeftBottomToTop: return "AAFScanningDirection_RightToLeftBottomToTop"; + case AAFScanningDirection_TopToBottomLeftToRight: return "AAFScanningDirection_TopToBottomLeftToRight"; + case AAFScanningDirection_TopToBottomRightToLeft: return "AAFScanningDirection_TopToBottomRightToLeft"; + case AAFScanningDirection_BottomToTopLeftToRight: return "AAFScanningDirection_BottomToTopLeftToRight"; + case AAFScanningDirection_BottomToTopRightToLeft: return "AAFScanningDirection_BottomToTopRightToLeft"; } - return L"Unknown AAFScanningDirection"; + return "Unknown AAFScanningDirection"; } -const wchar_t * aaft_ByteOrderToText( int16_t bo ) +const char * aaft_ByteOrderToText( int16_t bo ) { switch ( bo ) { case AAF_HEADER_BYTEORDER_LE: case AAF_PROPERTIES_BYTEORDER_LE: - return L"Little-Endian"; + return "Little-Endian"; case AAF_HEADER_BYTEORDER_BE: case AAF_PROPERTIES_BYTEORDER_BE: - return L"Big-Endian"; + return "Big-Endian"; } - return L"Unknown ByteOrder"; + return "Unknown ByteOrder"; } -const wchar_t * aaft_ElectroSpatialToText( aafElectroSpatialFormulation_t e ) +const char * aaft_ElectroSpatialToText( aafElectroSpatialFormulation_t e ) { switch ( e ) { - case AAFElectroSpatialFormulation_Default: return L"AAFElectroSpatialFormulation_Default"; - case AAFElectroSpatialFormulation_TwoChannelMode: return L"AAFElectroSpatialFormulation_TwoChannelMode"; - case AAFElectroSpatialFormulation_SingleChannelMode: return L"AAFElectroSpatialFormulation_SingleChannelMode"; - case AAFElectroSpatialFormulation_PrimarySecondaryMode: return L"AAFElectroSpatialFormulation_PrimarySecondaryMode"; - case AAFElectroSpatialFormulation_StereophonicMode: return L"AAFElectroSpatialFormulation_StereophonicMode"; - case AAFElectroSpatialFormulation_SingleChannelDoubleSamplingFrequencyMode: return L"AAFElectroSpatialFormulation_SingleChannelDoubleSamplingFrequencyMode"; - case AAFElectroSpatialFormulation_StereoLeftChannelDoubleSamplingFrequencyMode: return L"AAFElectroSpatialFormulation_StereoLeftChannelDoubleSamplingFrequencyMode"; - case AAFElectroSpatialFormulation_StereoRightChannelDoubleSamplingFrequencyMode: return L"AAFElectroSpatialFormulation_StereoRightChannelDoubleSamplingFrequencyMode"; - case AAFElectroSpatialFormulation_MultiChannelMode: return L"AAFElectroSpatialFormulation_MultiChannelMode"; + case AAFElectroSpatialFormulation_Default: return "AAFElectroSpatialFormulation_Default"; + case AAFElectroSpatialFormulation_TwoChannelMode: return "AAFElectroSpatialFormulation_TwoChannelMode"; + case AAFElectroSpatialFormulation_SingleChannelMode: return "AAFElectroSpatialFormulation_SingleChannelMode"; + case AAFElectroSpatialFormulation_PrimarySecondaryMode: return "AAFElectroSpatialFormulation_PrimarySecondaryMode"; + case AAFElectroSpatialFormulation_StereophonicMode: return "AAFElectroSpatialFormulation_StereophonicMode"; + case AAFElectroSpatialFormulation_SingleChannelDoubleSamplingFrequencyMode: return "AAFElectroSpatialFormulation_SingleChannelDoubleSamplingFrequencyMode"; + case AAFElectroSpatialFormulation_StereoLeftChannelDoubleSamplingFrequencyMode: return "AAFElectroSpatialFormulation_StereoLeftChannelDoubleSamplingFrequencyMode"; + case AAFElectroSpatialFormulation_StereoRightChannelDoubleSamplingFrequencyMode: return "AAFElectroSpatialFormulation_StereoRightChannelDoubleSamplingFrequencyMode"; + case AAFElectroSpatialFormulation_MultiChannelMode: return "AAFElectroSpatialFormulation_MultiChannelMode"; } - return L"Unknown AAFElectroSpatialFormulation"; + return "Unknown AAFElectroSpatialFormulation"; } -const wchar_t * aaft_StoredFormToText( enum aafStoredForm_e sf ) +const char * aaft_StoredFormToText( enum aafStoredForm_e sf ) { switch ( sf ) { - case SF_DATA: return L"SF_DATA"; - case SF_DATA_STREAM: return L"SF_DATA_STREAM"; - case SF_STRONG_OBJECT_REFERENCE: return L"SF_STRONG_OBJECT_REFERENCE"; - case SF_STRONG_OBJECT_REFERENCE_VECTOR: return L"SF_STRONG_OBJECT_REFERENCE_VECTOR"; - case SF_STRONG_OBJECT_REFERENCE_SET: return L"SF_STRONG_OBJECT_REFERENCE_SET"; - case SF_WEAK_OBJECT_REFERENCE: return L"SF_WEAK_OBJECT_REFERENCE"; - case SF_WEAK_OBJECT_REFERENCE_VECTOR: return L"SF_WEAK_OBJECT_REFERENCE_VECTOR"; - case SF_WEAK_OBJECT_REFERENCE_SET: return L"SF_WEAK_OBJECT_REFERENCE_SET"; - case SF_WEAK_OBJECT_REFERENCE_STORED_OBJECT_ID: return L"SF_WEAK_OBJECT_REFERENCE_STORED_OBJECT_ID"; - case SF_UNIQUE_OBJECT_ID: return L"SF_UNIQUE_OBJECT_ID"; - case SF_OPAQUE_STREAM: return L"SF_OPAQUE_STREAM"; + case SF_DATA: return "SF_DATA"; + case SF_DATA_STREAM: return "SF_DATA_STREAM"; + case SF_STRONG_OBJECT_REFERENCE: return "SF_STRONG_OBJECT_REFERENCE"; + case SF_STRONG_OBJECT_REFERENCE_VECTOR: return "SF_STRONG_OBJECT_REFERENCE_VECTOR"; + case SF_STRONG_OBJECT_REFERENCE_SET: return "SF_STRONG_OBJECT_REFERENCE_SET"; + case SF_WEAK_OBJECT_REFERENCE: return "SF_WEAK_OBJECT_REFERENCE"; + case SF_WEAK_OBJECT_REFERENCE_VECTOR: return "SF_WEAK_OBJECT_REFERENCE_VECTOR"; + case SF_WEAK_OBJECT_REFERENCE_SET: return "SF_WEAK_OBJECT_REFERENCE_SET"; + case SF_WEAK_OBJECT_REFERENCE_STORED_OBJECT_ID: return "SF_WEAK_OBJECT_REFERENCE_STORED_OBJECT_ID"; + case SF_UNIQUE_OBJECT_ID: return "SF_UNIQUE_OBJECT_ID"; + case SF_OPAQUE_STREAM: return "SF_OPAQUE_STREAM"; } - return L"Unknown StoredForm"; + return "Unknown StoredForm"; } -const wchar_t * aaft_OPDefToText( const aafUID_t *auid ) +const char * aaft_OPDefToText( const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; + return "n/a"; - if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return L"AAFUID_NULL"; - if ( aafUIDCmp( auid, &AAFOPDef_EditProtocol ) ) return L"AAFOPDef_EditProtocol"; - if ( aafUIDCmp( auid, &AAFOPDef_Unconstrained ) ) return L"AAFOPDef_Unconstrained"; + if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return "AAFUID_NULL"; + if ( aafUIDCmp( auid, &AAFOPDef_EditProtocol ) ) return "AAFOPDef_EditProtocol"; + if ( aafUIDCmp( auid, &AAFOPDef_Unconstrained ) ) return "AAFOPDef_Unconstrained"; - return L"Unknown AAFOPDef"; + return "Unknown AAFOPDef"; } -const wchar_t * aaft_TypeIDToText( const aafUID_t *auid ) +const char * aaft_TypeIDToText( const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; - - if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return L"AAFUID_NULL"; - if ( aafUIDCmp( auid, &AAFTypeID_UInt8 ) ) return L"AAFTypeID_UInt8"; - if ( aafUIDCmp( auid, &AAFTypeID_UInt16 ) ) return L"AAFTypeID_UInt16"; - if ( aafUIDCmp( auid, &AAFTypeID_UInt32 ) ) return L"AAFTypeID_UInt32"; - if ( aafUIDCmp( auid, &AAFTypeID_UInt64 ) ) return L"AAFTypeID_UInt64"; - if ( aafUIDCmp( auid, &AAFTypeID_Int8 ) ) return L"AAFTypeID_Int8"; - if ( aafUIDCmp( auid, &AAFTypeID_Int16 ) ) return L"AAFTypeID_Int16"; - if ( aafUIDCmp( auid, &AAFTypeID_Int32 ) ) return L"AAFTypeID_Int32"; - if ( aafUIDCmp( auid, &AAFTypeID_Int64 ) ) return L"AAFTypeID_Int64"; - if ( aafUIDCmp( auid, &AAFTypeID_PositionType ) ) return L"AAFTypeID_PositionType"; - if ( aafUIDCmp( auid, &AAFTypeID_LengthType ) ) return L"AAFTypeID_LengthType"; - if ( aafUIDCmp( auid, &AAFTypeID_JPEGTableIDType ) ) return L"AAFTypeID_JPEGTableIDType"; - if ( aafUIDCmp( auid, &AAFTypeID_PhaseFrameType ) ) return L"AAFTypeID_PhaseFrameType"; - if ( aafUIDCmp( auid, &AAFTypeID_AUID ) ) return L"AAFTypeID_AUID"; - if ( aafUIDCmp( auid, &AAFTypeID_MobIDType ) ) return L"AAFTypeID_MobIDType"; - if ( aafUIDCmp( auid, &AAFTypeID_Boolean ) ) return L"AAFTypeID_Boolean"; - if ( aafUIDCmp( auid, &AAFTypeID_Character ) ) return L"AAFTypeID_Character"; - if ( aafUIDCmp( auid, &AAFTypeID_String ) ) return L"AAFTypeID_String"; - if ( aafUIDCmp( auid, &AAFTypeID_ProductReleaseType ) ) return L"AAFTypeID_ProductReleaseType"; - if ( aafUIDCmp( auid, &AAFTypeID_TapeFormatType ) ) return L"AAFTypeID_TapeFormatType"; - if ( aafUIDCmp( auid, &AAFTypeID_VideoSignalType ) ) return L"AAFTypeID_VideoSignalType"; - if ( aafUIDCmp( auid, &AAFTypeID_TapeCaseType ) ) return L"AAFTypeID_TapeCaseType"; - if ( aafUIDCmp( auid, &AAFTypeID_ColorSitingType ) ) return L"AAFTypeID_ColorSitingType"; - if ( aafUIDCmp( auid, &AAFTypeID_EditHintType ) ) return L"AAFTypeID_EditHintType"; - if ( aafUIDCmp( auid, &AAFTypeID_FadeType ) ) return L"AAFTypeID_FadeType"; - if ( aafUIDCmp( auid, &AAFTypeID_LayoutType ) ) return L"AAFTypeID_LayoutType"; - if ( aafUIDCmp( auid, &AAFTypeID_TCSource ) ) return L"AAFTypeID_TCSource"; - if ( aafUIDCmp( auid, &AAFTypeID_PulldownDirectionType ) ) return L"AAFTypeID_PulldownDirectionType"; - if ( aafUIDCmp( auid, &AAFTypeID_PulldownKindType ) ) return L"AAFTypeID_PulldownKindType"; - if ( aafUIDCmp( auid, &AAFTypeID_EdgeType ) ) return L"AAFTypeID_EdgeType"; - if ( aafUIDCmp( auid, &AAFTypeID_FilmType ) ) return L"AAFTypeID_FilmType"; - if ( aafUIDCmp( auid, &AAFTypeID_RGBAComponentKind ) ) return L"AAFTypeID_RGBAComponentKind"; - if ( aafUIDCmp( auid, &AAFTypeID_ReferenceType ) ) return L"AAFTypeID_ReferenceType"; - if ( aafUIDCmp( auid, &AAFTypeID_AlphaTransparencyType ) ) return L"AAFTypeID_AlphaTransparencyType"; - if ( aafUIDCmp( auid, &AAFTypeID_FieldNumber ) ) return L"AAFTypeID_FieldNumber"; - if ( aafUIDCmp( auid, &AAFTypeID_ElectroSpatialFormulation ) ) return L"AAFTypeID_ElectroSpatialFormulation"; - if ( aafUIDCmp( auid, &AAFTypeID_EmphasisType ) ) return L"AAFTypeID_EmphasisType"; - if ( aafUIDCmp( auid, &AAFTypeID_AuxBitsModeType ) ) return L"AAFTypeID_AuxBitsModeType"; - if ( aafUIDCmp( auid, &AAFTypeID_ChannelStatusModeType ) ) return L"AAFTypeID_ChannelStatusModeType"; - if ( aafUIDCmp( auid, &AAFTypeID_UserDataModeType ) ) return L"AAFTypeID_UserDataModeType"; - if ( aafUIDCmp( auid, &AAFTypeID_SignalStandardType ) ) return L"AAFTypeID_SignalStandardType"; - if ( aafUIDCmp( auid, &AAFTypeID_ScanningDirectionType ) ) return L"AAFTypeID_ScanningDirectionType"; - if ( aafUIDCmp( auid, &AAFTypeID_ContentScanningType ) ) return L"AAFTypeID_ContentScanningType"; - if ( aafUIDCmp( auid, &AAFTypeID_TitleAlignmentType ) ) return L"AAFTypeID_TitleAlignmentType"; - if ( aafUIDCmp( auid, &AAFTypeID_OperationCategoryType ) ) return L"AAFTypeID_OperationCategoryType"; - if ( aafUIDCmp( auid, &AAFTypeID_TransferCharacteristicType ) ) return L"AAFTypeID_TransferCharacteristicType"; - if ( aafUIDCmp( auid, &AAFTypeID_PluginCategoryType ) ) return L"AAFTypeID_PluginCategoryType"; - if ( aafUIDCmp( auid, &AAFTypeID_UsageType ) ) return L"AAFTypeID_UsageType"; - if ( aafUIDCmp( auid, &AAFTypeID_ColorPrimariesType ) ) return L"AAFTypeID_ColorPrimariesType"; - if ( aafUIDCmp( auid, &AAFTypeID_CodingEquationsType ) ) return L"AAFTypeID_CodingEquationsType"; - if ( aafUIDCmp( auid, &AAFTypeID_Rational ) ) return L"AAFTypeID_Rational"; - if ( aafUIDCmp( auid, &AAFTypeID_ProductVersion ) ) return L"AAFTypeID_ProductVersion"; - if ( aafUIDCmp( auid, &AAFTypeID_VersionType ) ) return L"AAFTypeID_VersionType"; - if ( aafUIDCmp( auid, &AAFTypeID_RGBAComponent ) ) return L"AAFTypeID_RGBAComponent"; - if ( aafUIDCmp( auid, &AAFTypeID_DateStruct ) ) return L"AAFTypeID_DateStruct"; - if ( aafUIDCmp( auid, &AAFTypeID_TimeStruct ) ) return L"AAFTypeID_TimeStruct"; - if ( aafUIDCmp( auid, &AAFTypeID_TimeStamp ) ) return L"AAFTypeID_TimeStamp"; - if ( aafUIDCmp( auid, &AAFTypeID_UInt8Array ) ) return L"AAFTypeID_UInt8Array"; - if ( aafUIDCmp( auid, &AAFTypeID_UInt8Array12 ) ) return L"AAFTypeID_UInt8Array12"; - if ( aafUIDCmp( auid, &AAFTypeID_Int32Array ) ) return L"AAFTypeID_Int32Array"; - if ( aafUIDCmp( auid, &AAFTypeID_Int64Array ) ) return L"AAFTypeID_Int64Array"; - if ( aafUIDCmp( auid, &AAFTypeID_StringArray ) ) return L"AAFTypeID_StringArray"; - if ( aafUIDCmp( auid, &AAFTypeID_AUIDArray ) ) return L"AAFTypeID_AUIDArray"; - if ( aafUIDCmp( auid, &AAFTypeID_PositionArray ) ) return L"AAFTypeID_PositionArray"; - if ( aafUIDCmp( auid, &AAFTypeID_UInt8Array8 ) ) return L"AAFTypeID_UInt8Array8"; - if ( aafUIDCmp( auid, &AAFTypeID_UInt32Array ) ) return L"AAFTypeID_UInt32Array"; - if ( aafUIDCmp( auid, &AAFTypeID_ChannelStatusModeArray ) ) return L"AAFTypeID_ChannelStatusModeArray"; - if ( aafUIDCmp( auid, &AAFTypeID_UserDataModeArray ) ) return L"AAFTypeID_UserDataModeArray"; - if ( aafUIDCmp( auid, &AAFTypeID_RGBALayout ) ) return L"AAFTypeID_RGBALayout"; - if ( aafUIDCmp( auid, &AAFTypeID_AUIDSet ) ) return L"AAFTypeID_AUIDSet"; - if ( aafUIDCmp( auid, &AAFTypeID_UInt32Set ) ) return L"AAFTypeID_UInt32Set"; - if ( aafUIDCmp( auid, &AAFTypeID_DataValue ) ) return L"AAFTypeID_DataValue"; - if ( aafUIDCmp( auid, &AAFTypeID_Stream ) ) return L"AAFTypeID_Stream"; - if ( aafUIDCmp( auid, &AAFTypeID_Indirect ) ) return L"AAFTypeID_Indirect"; - if ( aafUIDCmp( auid, &AAFTypeID_Opaque ) ) return L"AAFTypeID_Opaque"; - if ( aafUIDCmp( auid, &AAFTypeID_ClassDefinitionWeakReference ) ) return L"AAFTypeID_ClassDefinitionWeakReference"; - if ( aafUIDCmp( auid, &AAFTypeID_ContainerDefinitionWeakReference ) ) return L"AAFTypeID_ContainerDefinitionWeakReference"; - if ( aafUIDCmp( auid, &AAFTypeID_DataDefinitionWeakReference ) ) return L"AAFTypeID_DataDefinitionWeakReference"; - if ( aafUIDCmp( auid, &AAFTypeID_InterpolationDefinitionWeakReference ) ) return L"AAFTypeID_InterpolationDefinitionWeakReference"; - if ( aafUIDCmp( auid, &AAFTypeID_MobWeakReference ) ) return L"AAFTypeID_MobWeakReference"; - if ( aafUIDCmp( auid, &AAFTypeID_OperationDefinitionWeakReference ) ) return L"AAFTypeID_OperationDefinitionWeakReference"; - if ( aafUIDCmp( auid, &AAFTypeID_ParameterDefinitionWeakReference ) ) return L"AAFTypeID_ParameterDefinitionWeakReference"; - if ( aafUIDCmp( auid, &AAFTypeID_TypeDefinitionWeakReference ) ) return L"AAFTypeID_TypeDefinitionWeakReference"; - if ( aafUIDCmp( auid, &AAFTypeID_PluginDefinitionWeakReference ) ) return L"AAFTypeID_PluginDefinitionWeakReference"; - if ( aafUIDCmp( auid, &AAFTypeID_CodecDefinitionWeakReference ) ) return L"AAFTypeID_CodecDefinitionWeakReference"; - if ( aafUIDCmp( auid, &AAFTypeID_PropertyDefinitionWeakReference ) ) return L"AAFTypeID_PropertyDefinitionWeakReference"; - if ( aafUIDCmp( auid, &AAFTypeID_ContentStorageStrongReference ) ) return L"AAFTypeID_ContentStorageStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_DictionaryStrongReference ) ) return L"AAFTypeID_DictionaryStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_EssenceDescriptorStrongReference ) ) return L"AAFTypeID_EssenceDescriptorStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_NetworkLocatorStrongReference ) ) return L"AAFTypeID_NetworkLocatorStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_OperationGroupStrongReference ) ) return L"AAFTypeID_OperationGroupStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_SegmentStrongReference ) ) return L"AAFTypeID_SegmentStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_SourceClipStrongReference ) ) return L"AAFTypeID_SourceClipStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_SourceReferenceStrongReference ) ) return L"AAFTypeID_SourceReferenceStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_ClassDefinitionStrongReference ) ) return L"AAFTypeID_ClassDefinitionStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_CodecDefinitionStrongReference ) ) return L"AAFTypeID_CodecDefinitionStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_ComponentStrongReference ) ) return L"AAFTypeID_ComponentStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_ContainerDefinitionStrongReference ) ) return L"AAFTypeID_ContainerDefinitionStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_ControlPointStrongReference ) ) return L"AAFTypeID_ControlPointStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_DataDefinitionStrongReference ) ) return L"AAFTypeID_DataDefinitionStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_EssenceDataStrongReference ) ) return L"AAFTypeID_EssenceDataStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_IdentificationStrongReference ) ) return L"AAFTypeID_IdentificationStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_InterpolationDefinitionStrongReference ) ) return L"AAFTypeID_InterpolationDefinitionStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_LocatorStrongReference ) ) return L"AAFTypeID_LocatorStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_MobStrongReference ) ) return L"AAFTypeID_MobStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_MobSlotStrongReference ) ) return L"AAFTypeID_MobSlotStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_OperationDefinitionStrongReference ) ) return L"AAFTypeID_OperationDefinitionStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_ParameterStrongReference ) ) return L"AAFTypeID_ParameterStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_ParameterDefinitionStrongReference ) ) return L"AAFTypeID_ParameterDefinitionStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_PluginDefinitionStrongReference ) ) return L"AAFTypeID_PluginDefinitionStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_PropertyDefinitionStrongReference ) ) return L"AAFTypeID_PropertyDefinitionStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_TaggedValueStrongReference ) ) return L"AAFTypeID_TaggedValueStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_TypeDefinitionStrongReference ) ) return L"AAFTypeID_TypeDefinitionStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_KLVDataStrongReference ) ) return L"AAFTypeID_KLVDataStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_FileDescriptorStrongReference ) ) return L"AAFTypeID_FileDescriptorStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_RIFFChunkStrongReference ) ) return L"AAFTypeID_RIFFChunkStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_DescriptiveFrameworkStrongReference ) ) return L"AAFTypeID_DescriptiveFrameworkStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_KLVDataDefinitionStrongReference ) ) return L"AAFTypeID_KLVDataDefinitionStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_TaggedValueDefinitionStrongReference ) ) return L"AAFTypeID_TaggedValueDefinitionStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_DescriptiveObjectStrongReference ) ) return L"AAFTypeID_DescriptiveObjectStrongReference"; - if ( aafUIDCmp( auid, &AAFTypeID_DataDefinitionWeakReferenceSet ) ) return L"AAFTypeID_DataDefinitionWeakReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_ParameterDefinitionWeakReferenceSet ) ) return L"AAFTypeID_ParameterDefinitionWeakReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_PluginDefinitionWeakReferenceSet ) ) return L"AAFTypeID_PluginDefinitionWeakReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_PropertyDefinitionWeakReferenceSet ) ) return L"AAFTypeID_PropertyDefinitionWeakReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_OperationDefinitionWeakReferenceVector ) ) return L"AAFTypeID_OperationDefinitionWeakReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_TypeDefinitionWeakReferenceVector ) ) return L"AAFTypeID_TypeDefinitionWeakReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_DataDefinitionWeakReferenceVector ) ) return L"AAFTypeID_DataDefinitionWeakReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_ClassDefinitionStrongReferenceSet ) ) return L"AAFTypeID_ClassDefinitionStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_CodecDefinitionStrongReferenceSet ) ) return L"AAFTypeID_CodecDefinitionStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_ContainerDefinitionStrongReferenceSet ) ) return L"AAFTypeID_ContainerDefinitionStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_DataDefinitionStrongReferenceSet ) ) return L"AAFTypeID_DataDefinitionStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_EssenceDataStrongReferenceSet ) ) return L"AAFTypeID_EssenceDataStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_InterpolationDefinitionStrongReferenceSet ) ) return L"AAFTypeID_InterpolationDefinitionStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_MobStrongReferenceSet ) ) return L"AAFTypeID_MobStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_OperationDefinitionStrongReferenceSet ) ) return L"AAFTypeID_OperationDefinitionStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_ParameterDefinitionStrongReferenceSet ) ) return L"AAFTypeID_ParameterDefinitionStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_PluginDefinitionStrongReferenceSet ) ) return L"AAFTypeID_PluginDefinitionStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_PropertyDefinitionStrongReferenceSet ) ) return L"AAFTypeID_PropertyDefinitionStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_TypeDefinitionStrongReferenceSet ) ) return L"AAFTypeID_TypeDefinitionStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_KLVDataDefinitionStrongReferenceSet ) ) return L"AAFTypeID_KLVDataDefinitionStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_TaggedValueDefinitionStrongReferenceSet ) ) return L"AAFTypeID_TaggedValueDefinitionStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_DescriptiveObjectStrongReferenceSet ) ) return L"AAFTypeID_DescriptiveObjectStrongReferenceSet"; - if ( aafUIDCmp( auid, &AAFTypeID_ComponentStrongReferenceVector ) ) return L"AAFTypeID_ComponentStrongReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_ControlPointStrongReferenceVector ) ) return L"AAFTypeID_ControlPointStrongReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_IdentificationStrongReferenceVector ) ) return L"AAFTypeID_IdentificationStrongReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_LocatorStrongReferenceVector ) ) return L"AAFTypeID_LocatorStrongReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_MobSlotStrongReferenceVector ) ) return L"AAFTypeID_MobSlotStrongReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_SegmentStrongReferenceVector ) ) return L"AAFTypeID_SegmentStrongReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_SourceReferenceStrongReferenceVector ) ) return L"AAFTypeID_SourceReferenceStrongReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_TaggedValueStrongReferenceVector ) ) return L"AAFTypeID_TaggedValueStrongReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_KLVDataStrongReferenceVector ) ) return L"AAFTypeID_KLVDataStrongReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_ParameterStrongReferenceVector ) ) return L"AAFTypeID_ParameterStrongReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_FileDescriptorStrongReferenceVector ) ) return L"AAFTypeID_FileDescriptorStrongReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_RIFFChunkStrongReferenceVector ) ) return L"AAFTypeID_RIFFChunkStrongReferenceVector"; - if ( aafUIDCmp( auid, &AAFTypeID_DescriptiveObjectStrongReferenceVector ) ) return L"AAFTypeID_DescriptiveObjectStrongReferenceVector"; - - return L"Unknown AAFTypeID"; + return "n/a"; + + if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return "AAFUID_NULL"; + if ( aafUIDCmp( auid, &AAFTypeID_UInt8 ) ) return "AAFTypeID_UInt8"; + if ( aafUIDCmp( auid, &AAFTypeID_UInt16 ) ) return "AAFTypeID_UInt16"; + if ( aafUIDCmp( auid, &AAFTypeID_UInt32 ) ) return "AAFTypeID_UInt32"; + if ( aafUIDCmp( auid, &AAFTypeID_UInt64 ) ) return "AAFTypeID_UInt64"; + if ( aafUIDCmp( auid, &AAFTypeID_Int8 ) ) return "AAFTypeID_Int8"; + if ( aafUIDCmp( auid, &AAFTypeID_Int16 ) ) return "AAFTypeID_Int16"; + if ( aafUIDCmp( auid, &AAFTypeID_Int32 ) ) return "AAFTypeID_Int32"; + if ( aafUIDCmp( auid, &AAFTypeID_Int64 ) ) return "AAFTypeID_Int64"; + if ( aafUIDCmp( auid, &AAFTypeID_PositionType ) ) return "AAFTypeID_PositionType"; + if ( aafUIDCmp( auid, &AAFTypeID_LengthType ) ) return "AAFTypeID_LengthType"; + if ( aafUIDCmp( auid, &AAFTypeID_JPEGTableIDType ) ) return "AAFTypeID_JPEGTableIDType"; + if ( aafUIDCmp( auid, &AAFTypeID_PhaseFrameType ) ) return "AAFTypeID_PhaseFrameType"; + if ( aafUIDCmp( auid, &AAFTypeID_AUID ) ) return "AAFTypeID_AUID"; + if ( aafUIDCmp( auid, &AAFTypeID_MobIDType ) ) return "AAFTypeID_MobIDType"; + if ( aafUIDCmp( auid, &AAFTypeID_Boolean ) ) return "AAFTypeID_Boolean"; + if ( aafUIDCmp( auid, &AAFTypeID_Character ) ) return "AAFTypeID_Character"; + if ( aafUIDCmp( auid, &AAFTypeID_String ) ) return "AAFTypeID_String"; + if ( aafUIDCmp( auid, &AAFTypeID_ProductReleaseType ) ) return "AAFTypeID_ProductReleaseType"; + if ( aafUIDCmp( auid, &AAFTypeID_TapeFormatType ) ) return "AAFTypeID_TapeFormatType"; + if ( aafUIDCmp( auid, &AAFTypeID_VideoSignalType ) ) return "AAFTypeID_VideoSignalType"; + if ( aafUIDCmp( auid, &AAFTypeID_TapeCaseType ) ) return "AAFTypeID_TapeCaseType"; + if ( aafUIDCmp( auid, &AAFTypeID_ColorSitingType ) ) return "AAFTypeID_ColorSitingType"; + if ( aafUIDCmp( auid, &AAFTypeID_EditHintType ) ) return "AAFTypeID_EditHintType"; + if ( aafUIDCmp( auid, &AAFTypeID_FadeType ) ) return "AAFTypeID_FadeType"; + if ( aafUIDCmp( auid, &AAFTypeID_LayoutType ) ) return "AAFTypeID_LayoutType"; + if ( aafUIDCmp( auid, &AAFTypeID_TCSource ) ) return "AAFTypeID_TCSource"; + if ( aafUIDCmp( auid, &AAFTypeID_PulldownDirectionType ) ) return "AAFTypeID_PulldownDirectionType"; + if ( aafUIDCmp( auid, &AAFTypeID_PulldownKindType ) ) return "AAFTypeID_PulldownKindType"; + if ( aafUIDCmp( auid, &AAFTypeID_EdgeType ) ) return "AAFTypeID_EdgeType"; + if ( aafUIDCmp( auid, &AAFTypeID_FilmType ) ) return "AAFTypeID_FilmType"; + if ( aafUIDCmp( auid, &AAFTypeID_RGBAComponentKind ) ) return "AAFTypeID_RGBAComponentKind"; + if ( aafUIDCmp( auid, &AAFTypeID_ReferenceType ) ) return "AAFTypeID_ReferenceType"; + if ( aafUIDCmp( auid, &AAFTypeID_AlphaTransparencyType ) ) return "AAFTypeID_AlphaTransparencyType"; + if ( aafUIDCmp( auid, &AAFTypeID_FieldNumber ) ) return "AAFTypeID_FieldNumber"; + if ( aafUIDCmp( auid, &AAFTypeID_ElectroSpatialFormulation ) ) return "AAFTypeID_ElectroSpatialFormulation"; + if ( aafUIDCmp( auid, &AAFTypeID_EmphasisType ) ) return "AAFTypeID_EmphasisType"; + if ( aafUIDCmp( auid, &AAFTypeID_AuxBitsModeType ) ) return "AAFTypeID_AuxBitsModeType"; + if ( aafUIDCmp( auid, &AAFTypeID_ChannelStatusModeType ) ) return "AAFTypeID_ChannelStatusModeType"; + if ( aafUIDCmp( auid, &AAFTypeID_UserDataModeType ) ) return "AAFTypeID_UserDataModeType"; + if ( aafUIDCmp( auid, &AAFTypeID_SignalStandardType ) ) return "AAFTypeID_SignalStandardType"; + if ( aafUIDCmp( auid, &AAFTypeID_ScanningDirectionType ) ) return "AAFTypeID_ScanningDirectionType"; + if ( aafUIDCmp( auid, &AAFTypeID_ContentScanningType ) ) return "AAFTypeID_ContentScanningType"; + if ( aafUIDCmp( auid, &AAFTypeID_TitleAlignmentType ) ) return "AAFTypeID_TitleAlignmentType"; + if ( aafUIDCmp( auid, &AAFTypeID_OperationCategoryType ) ) return "AAFTypeID_OperationCategoryType"; + if ( aafUIDCmp( auid, &AAFTypeID_TransferCharacteristicType ) ) return "AAFTypeID_TransferCharacteristicType"; + if ( aafUIDCmp( auid, &AAFTypeID_PluginCategoryType ) ) return "AAFTypeID_PluginCategoryType"; + if ( aafUIDCmp( auid, &AAFTypeID_UsageType ) ) return "AAFTypeID_UsageType"; + if ( aafUIDCmp( auid, &AAFTypeID_ColorPrimariesType ) ) return "AAFTypeID_ColorPrimariesType"; + if ( aafUIDCmp( auid, &AAFTypeID_CodingEquationsType ) ) return "AAFTypeID_CodingEquationsType"; + if ( aafUIDCmp( auid, &AAFTypeID_Rational ) ) return "AAFTypeID_Rational"; + if ( aafUIDCmp( auid, &AAFTypeID_ProductVersion ) ) return "AAFTypeID_ProductVersion"; + if ( aafUIDCmp( auid, &AAFTypeID_VersionType ) ) return "AAFTypeID_VersionType"; + if ( aafUIDCmp( auid, &AAFTypeID_RGBAComponent ) ) return "AAFTypeID_RGBAComponent"; + if ( aafUIDCmp( auid, &AAFTypeID_DateStruct ) ) return "AAFTypeID_DateStruct"; + if ( aafUIDCmp( auid, &AAFTypeID_TimeStruct ) ) return "AAFTypeID_TimeStruct"; + if ( aafUIDCmp( auid, &AAFTypeID_TimeStamp ) ) return "AAFTypeID_TimeStamp"; + if ( aafUIDCmp( auid, &AAFTypeID_UInt8Array ) ) return "AAFTypeID_UInt8Array"; + if ( aafUIDCmp( auid, &AAFTypeID_UInt8Array12 ) ) return "AAFTypeID_UInt8Array12"; + if ( aafUIDCmp( auid, &AAFTypeID_Int32Array ) ) return "AAFTypeID_Int32Array"; + if ( aafUIDCmp( auid, &AAFTypeID_Int64Array ) ) return "AAFTypeID_Int64Array"; + if ( aafUIDCmp( auid, &AAFTypeID_StringArray ) ) return "AAFTypeID_StringArray"; + if ( aafUIDCmp( auid, &AAFTypeID_AUIDArray ) ) return "AAFTypeID_AUIDArray"; + if ( aafUIDCmp( auid, &AAFTypeID_PositionArray ) ) return "AAFTypeID_PositionArray"; + if ( aafUIDCmp( auid, &AAFTypeID_UInt8Array8 ) ) return "AAFTypeID_UInt8Array8"; + if ( aafUIDCmp( auid, &AAFTypeID_UInt32Array ) ) return "AAFTypeID_UInt32Array"; + if ( aafUIDCmp( auid, &AAFTypeID_ChannelStatusModeArray ) ) return "AAFTypeID_ChannelStatusModeArray"; + if ( aafUIDCmp( auid, &AAFTypeID_UserDataModeArray ) ) return "AAFTypeID_UserDataModeArray"; + if ( aafUIDCmp( auid, &AAFTypeID_RGBALayout ) ) return "AAFTypeID_RGBALayout"; + if ( aafUIDCmp( auid, &AAFTypeID_AUIDSet ) ) return "AAFTypeID_AUIDSet"; + if ( aafUIDCmp( auid, &AAFTypeID_UInt32Set ) ) return "AAFTypeID_UInt32Set"; + if ( aafUIDCmp( auid, &AAFTypeID_DataValue ) ) return "AAFTypeID_DataValue"; + if ( aafUIDCmp( auid, &AAFTypeID_Stream ) ) return "AAFTypeID_Stream"; + if ( aafUIDCmp( auid, &AAFTypeID_Indirect ) ) return "AAFTypeID_Indirect"; + if ( aafUIDCmp( auid, &AAFTypeID_Opaque ) ) return "AAFTypeID_Opaque"; + if ( aafUIDCmp( auid, &AAFTypeID_ClassDefinitionWeakReference ) ) return "AAFTypeID_ClassDefinitionWeakReference"; + if ( aafUIDCmp( auid, &AAFTypeID_ContainerDefinitionWeakReference ) ) return "AAFTypeID_ContainerDefinitionWeakReference"; + if ( aafUIDCmp( auid, &AAFTypeID_DataDefinitionWeakReference ) ) return "AAFTypeID_DataDefinitionWeakReference"; + if ( aafUIDCmp( auid, &AAFTypeID_InterpolationDefinitionWeakReference ) ) return "AAFTypeID_InterpolationDefinitionWeakReference"; + if ( aafUIDCmp( auid, &AAFTypeID_MobWeakReference ) ) return "AAFTypeID_MobWeakReference"; + if ( aafUIDCmp( auid, &AAFTypeID_OperationDefinitionWeakReference ) ) return "AAFTypeID_OperationDefinitionWeakReference"; + if ( aafUIDCmp( auid, &AAFTypeID_ParameterDefinitionWeakReference ) ) return "AAFTypeID_ParameterDefinitionWeakReference"; + if ( aafUIDCmp( auid, &AAFTypeID_TypeDefinitionWeakReference ) ) return "AAFTypeID_TypeDefinitionWeakReference"; + if ( aafUIDCmp( auid, &AAFTypeID_PluginDefinitionWeakReference ) ) return "AAFTypeID_PluginDefinitionWeakReference"; + if ( aafUIDCmp( auid, &AAFTypeID_CodecDefinitionWeakReference ) ) return "AAFTypeID_CodecDefinitionWeakReference"; + if ( aafUIDCmp( auid, &AAFTypeID_PropertyDefinitionWeakReference ) ) return "AAFTypeID_PropertyDefinitionWeakReference"; + if ( aafUIDCmp( auid, &AAFTypeID_ContentStorageStrongReference ) ) return "AAFTypeID_ContentStorageStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_DictionaryStrongReference ) ) return "AAFTypeID_DictionaryStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_EssenceDescriptorStrongReference ) ) return "AAFTypeID_EssenceDescriptorStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_NetworkLocatorStrongReference ) ) return "AAFTypeID_NetworkLocatorStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_OperationGroupStrongReference ) ) return "AAFTypeID_OperationGroupStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_SegmentStrongReference ) ) return "AAFTypeID_SegmentStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_SourceClipStrongReference ) ) return "AAFTypeID_SourceClipStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_SourceReferenceStrongReference ) ) return "AAFTypeID_SourceReferenceStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_ClassDefinitionStrongReference ) ) return "AAFTypeID_ClassDefinitionStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_CodecDefinitionStrongReference ) ) return "AAFTypeID_CodecDefinitionStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_ComponentStrongReference ) ) return "AAFTypeID_ComponentStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_ContainerDefinitionStrongReference ) ) return "AAFTypeID_ContainerDefinitionStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_ControlPointStrongReference ) ) return "AAFTypeID_ControlPointStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_DataDefinitionStrongReference ) ) return "AAFTypeID_DataDefinitionStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_EssenceDataStrongReference ) ) return "AAFTypeID_EssenceDataStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_IdentificationStrongReference ) ) return "AAFTypeID_IdentificationStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_InterpolationDefinitionStrongReference ) ) return "AAFTypeID_InterpolationDefinitionStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_LocatorStrongReference ) ) return "AAFTypeID_LocatorStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_MobStrongReference ) ) return "AAFTypeID_MobStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_MobSlotStrongReference ) ) return "AAFTypeID_MobSlotStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_OperationDefinitionStrongReference ) ) return "AAFTypeID_OperationDefinitionStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_ParameterStrongReference ) ) return "AAFTypeID_ParameterStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_ParameterDefinitionStrongReference ) ) return "AAFTypeID_ParameterDefinitionStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_PluginDefinitionStrongReference ) ) return "AAFTypeID_PluginDefinitionStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_PropertyDefinitionStrongReference ) ) return "AAFTypeID_PropertyDefinitionStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_TaggedValueStrongReference ) ) return "AAFTypeID_TaggedValueStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_TypeDefinitionStrongReference ) ) return "AAFTypeID_TypeDefinitionStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_KLVDataStrongReference ) ) return "AAFTypeID_KLVDataStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_FileDescriptorStrongReference ) ) return "AAFTypeID_FileDescriptorStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_RIFFChunkStrongReference ) ) return "AAFTypeID_RIFFChunkStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_DescriptiveFrameworkStrongReference ) ) return "AAFTypeID_DescriptiveFrameworkStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_KLVDataDefinitionStrongReference ) ) return "AAFTypeID_KLVDataDefinitionStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_TaggedValueDefinitionStrongReference ) ) return "AAFTypeID_TaggedValueDefinitionStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_DescriptiveObjectStrongReference ) ) return "AAFTypeID_DescriptiveObjectStrongReference"; + if ( aafUIDCmp( auid, &AAFTypeID_DataDefinitionWeakReferenceSet ) ) return "AAFTypeID_DataDefinitionWeakReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_ParameterDefinitionWeakReferenceSet ) ) return "AAFTypeID_ParameterDefinitionWeakReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_PluginDefinitionWeakReferenceSet ) ) return "AAFTypeID_PluginDefinitionWeakReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_PropertyDefinitionWeakReferenceSet ) ) return "AAFTypeID_PropertyDefinitionWeakReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_OperationDefinitionWeakReferenceVector ) ) return "AAFTypeID_OperationDefinitionWeakReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_TypeDefinitionWeakReferenceVector ) ) return "AAFTypeID_TypeDefinitionWeakReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_DataDefinitionWeakReferenceVector ) ) return "AAFTypeID_DataDefinitionWeakReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_ClassDefinitionStrongReferenceSet ) ) return "AAFTypeID_ClassDefinitionStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_CodecDefinitionStrongReferenceSet ) ) return "AAFTypeID_CodecDefinitionStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_ContainerDefinitionStrongReferenceSet ) ) return "AAFTypeID_ContainerDefinitionStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_DataDefinitionStrongReferenceSet ) ) return "AAFTypeID_DataDefinitionStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_EssenceDataStrongReferenceSet ) ) return "AAFTypeID_EssenceDataStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_InterpolationDefinitionStrongReferenceSet ) ) return "AAFTypeID_InterpolationDefinitionStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_MobStrongReferenceSet ) ) return "AAFTypeID_MobStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_OperationDefinitionStrongReferenceSet ) ) return "AAFTypeID_OperationDefinitionStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_ParameterDefinitionStrongReferenceSet ) ) return "AAFTypeID_ParameterDefinitionStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_PluginDefinitionStrongReferenceSet ) ) return "AAFTypeID_PluginDefinitionStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_PropertyDefinitionStrongReferenceSet ) ) return "AAFTypeID_PropertyDefinitionStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_TypeDefinitionStrongReferenceSet ) ) return "AAFTypeID_TypeDefinitionStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_KLVDataDefinitionStrongReferenceSet ) ) return "AAFTypeID_KLVDataDefinitionStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_TaggedValueDefinitionStrongReferenceSet ) ) return "AAFTypeID_TaggedValueDefinitionStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_DescriptiveObjectStrongReferenceSet ) ) return "AAFTypeID_DescriptiveObjectStrongReferenceSet"; + if ( aafUIDCmp( auid, &AAFTypeID_ComponentStrongReferenceVector ) ) return "AAFTypeID_ComponentStrongReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_ControlPointStrongReferenceVector ) ) return "AAFTypeID_ControlPointStrongReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_IdentificationStrongReferenceVector ) ) return "AAFTypeID_IdentificationStrongReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_LocatorStrongReferenceVector ) ) return "AAFTypeID_LocatorStrongReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_MobSlotStrongReferenceVector ) ) return "AAFTypeID_MobSlotStrongReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_SegmentStrongReferenceVector ) ) return "AAFTypeID_SegmentStrongReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_SourceReferenceStrongReferenceVector ) ) return "AAFTypeID_SourceReferenceStrongReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_TaggedValueStrongReferenceVector ) ) return "AAFTypeID_TaggedValueStrongReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_KLVDataStrongReferenceVector ) ) return "AAFTypeID_KLVDataStrongReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_ParameterStrongReferenceVector ) ) return "AAFTypeID_ParameterStrongReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_FileDescriptorStrongReferenceVector ) ) return "AAFTypeID_FileDescriptorStrongReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_RIFFChunkStrongReferenceVector ) ) return "AAFTypeID_RIFFChunkStrongReferenceVector"; + if ( aafUIDCmp( auid, &AAFTypeID_DescriptiveObjectStrongReferenceVector ) ) return "AAFTypeID_DescriptiveObjectStrongReferenceVector"; + + return "Unknown AAFTypeID"; } -const wchar_t * aaft_DataDefToText( AAF_Data *aafd, const aafUID_t *auid ) +const char * aaft_DataDefToText( AAF_Data *aafd, const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; + return "n/a"; - if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return L"AAFUID_NULL"; - if ( aafUIDCmp( auid, &AAFDataDef_Picture ) ) return L"AAFDataDef_Picture"; - if ( aafUIDCmp( auid, &AAFDataDef_LegacyPicture ) ) return L"AAFDataDef_LegacyPicture"; - if ( aafUIDCmp( auid, &AAFDataDef_Matte ) ) return L"AAFDataDef_Matte"; - if ( aafUIDCmp( auid, &AAFDataDef_PictureWithMatte ) ) return L"AAFDataDef_PictureWithMatte"; - if ( aafUIDCmp( auid, &AAFDataDef_Sound ) ) return L"AAFDataDef_Sound"; - if ( aafUIDCmp( auid, &AAFDataDef_LegacySound ) ) return L"AAFDataDef_LegacySound"; - if ( aafUIDCmp( auid, &AAFDataDef_Timecode ) ) return L"AAFDataDef_Timecode"; - if ( aafUIDCmp( auid, &AAFDataDef_LegacyTimecode ) ) return L"AAFDataDef_LegacyTimecode"; - if ( aafUIDCmp( auid, &AAFDataDef_Edgecode ) ) return L"AAFDataDef_Edgecode"; - if ( aafUIDCmp( auid, &AAFDataDef_DescriptiveMetadata ) ) return L"AAFDataDef_DescriptiveMetadata"; - if ( aafUIDCmp( auid, &AAFDataDef_Auxiliary ) ) return L"AAFDataDef_Auxiliary"; - if ( aafUIDCmp( auid, &AAFDataDef_Unknown ) ) return L"AAFDataDef_Unknown"; + if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return "AAFUID_NULL"; + if ( aafUIDCmp( auid, &AAFDataDef_Picture ) ) return "AAFDataDef_Picture"; + if ( aafUIDCmp( auid, &AAFDataDef_LegacyPicture ) ) return "AAFDataDef_LegacyPicture"; + if ( aafUIDCmp( auid, &AAFDataDef_Matte ) ) return "AAFDataDef_Matte"; + if ( aafUIDCmp( auid, &AAFDataDef_PictureWithMatte ) ) return "AAFDataDef_PictureWithMatte"; + if ( aafUIDCmp( auid, &AAFDataDef_Sound ) ) return "AAFDataDef_Sound"; + if ( aafUIDCmp( auid, &AAFDataDef_LegacySound ) ) return "AAFDataDef_LegacySound"; + if ( aafUIDCmp( auid, &AAFDataDef_Timecode ) ) return "AAFDataDef_Timecode"; + if ( aafUIDCmp( auid, &AAFDataDef_LegacyTimecode ) ) return "AAFDataDef_LegacyTimecode"; + if ( aafUIDCmp( auid, &AAFDataDef_Edgecode ) ) return "AAFDataDef_Edgecode"; + if ( aafUIDCmp( auid, &AAFDataDef_DescriptiveMetadata ) ) return "AAFDataDef_DescriptiveMetadata"; + if ( aafUIDCmp( auid, &AAFDataDef_Auxiliary ) ) return "AAFDataDef_Auxiliary"; + if ( aafUIDCmp( auid, &AAFDataDef_Unknown ) ) return "AAFDataDef_Unknown"; - static wchar_t TEXTDataDef[1024]; + static char TEXTDataDef[1024]; aafObject *DataDefinitions = aaf_get_propertyValue( aafd->Dictionary, PID_Dictionary_DataDefinitions, &AAFTypeID_DataDefinitionStrongReferenceSet ); aafObject *DataDefinition = NULL; - aaf_foreach_ObjectInSet( &DataDefinition, DataDefinitions, NULL ) { + while ( _aaf_foreach_ObjectInSet( &DataDefinition, DataDefinitions, NULL ) ) { aafUID_t *DataDefIdent = aaf_get_propertyValue( DataDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID ); if ( DataDefIdent && aafUIDCmp( DataDefIdent, auid ) ) { - wchar_t *name = aaf_get_propertyValue( DataDefinition, PID_DefinitionObject_Name, &AAFTypeID_String ); - swprintf( TEXTDataDef, 1024, L"%" WPRIws, name ); + + char *name = aaf_get_propertyValue( DataDefinition, PID_DefinitionObject_Name, &AAFTypeID_String ); + + if ( !name ) { + error( "Could not retrieve DataDefinition::Name" ); + return NULL; + } + + int rc = snprintf( TEXTDataDef, sizeof(TEXTDataDef), "%s", name ); + + assert( rc >= 0 && (size_t)rc < sizeof(TEXTDataDef) ); + + // if ( rc < 0 || (size_t)rc >= 1024 ) { + // error( "snprintf() error" ); + // return NULL; + // } + free( name ); return TEXTDataDef; @@ -672,62 +765,77 @@ const wchar_t * aaft_DataDefToText( AAF_Data *aafd, const aafUID_t *auid ) } - return L"Unknown AAFDataDef"; + return "Unknown AAFDataDef"; } -const wchar_t * aaft_OperationDefToText( AAF_Data *aafd, const aafUID_t *auid ) +const char * aaft_OperationDefToText( AAF_Data *aafd, const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; - - if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return L"AAFUID_NULL"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoDissolve ) ) return L"AAFOperationDef_VideoDissolve"; - if ( aafUIDCmp( auid, &AAFOperationDef_SMPTEVideoWipe ) ) return L"AAFOperationDef_SMPTEVideoWipe"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoSpeedControl ) ) return L"AAFOperationDef_VideoSpeedControl"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoRepeat ) ) return L"AAFOperationDef_VideoRepeat"; - if ( aafUIDCmp( auid, &AAFOperationDef_Flip ) ) return L"AAFOperationDef_Flip"; - if ( aafUIDCmp( auid, &AAFOperationDef_Flop ) ) return L"AAFOperationDef_Flop"; - if ( aafUIDCmp( auid, &AAFOperationDef_FlipFlop ) ) return L"AAFOperationDef_FlipFlop"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoPosition ) ) return L"AAFOperationDef_VideoPosition"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoCrop ) ) return L"AAFOperationDef_VideoCrop"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoScale ) ) return L"AAFOperationDef_VideoScale"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoRotate ) ) return L"AAFOperationDef_VideoRotate"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoCornerPinning ) ) return L"AAFOperationDef_VideoCornerPinning"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoAlphaWithinVideoKey ) ) return L"AAFOperationDef_VideoAlphaWithinVideoKey"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoSeparateAlphaKey ) ) return L"AAFOperationDef_VideoSeparateAlphaKey"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoLuminanceKey ) ) return L"AAFOperationDef_VideoLuminanceKey"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoChromaKey ) ) return L"AAFOperationDef_VideoChromaKey"; - if ( aafUIDCmp( auid, &AAFOperationDef_MonoAudioGain ) ) return L"AAFOperationDef_MonoAudioGain"; - if ( aafUIDCmp( auid, &AAFOperationDef_MonoAudioPan ) ) return L"AAFOperationDef_MonoAudioPan"; - if ( aafUIDCmp( auid, &AAFOperationDef_MonoAudioDissolve ) ) return L"AAFOperationDef_MonoAudioDissolve"; - if ( aafUIDCmp( auid, &AAFOperationDef_TwoParameterMonoAudioDissolve ) ) return L"AAFOperationDef_TwoParameterMonoAudioDissolve"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoOpacity ) ) return L"AAFOperationDef_VideoOpacity"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoTitle ) ) return L"AAFOperationDef_VideoTitle"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoColor ) ) return L"AAFOperationDef_VideoColor"; - if ( aafUIDCmp( auid, &AAFOperationDef_Unknown ) ) return L"AAFOperationDef_Unknown"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoFadeToBlack ) ) return L"AAFOperationDef_VideoFadeToBlack"; - if ( aafUIDCmp( auid, &AAFOperationDef_PictureWithMate ) ) return L"AAFOperationDef_PictureWithMate"; - if ( aafUIDCmp( auid, &AAFOperationDef_VideoFrameToMask ) ) return L"AAFOperationDef_VideoFrameToMask"; - if ( aafUIDCmp( auid, &AAFOperationDef_StereoAudioDissolve ) ) return L"AAFOperationDef_StereoAudioDissolve"; - if ( aafUIDCmp( auid, &AAFOperationDef_StereoAudioGain ) ) return L"AAFOperationDef_StereoAudioGain"; - if ( aafUIDCmp( auid, &AAFOperationDef_MonoAudioMixdown ) ) return L"AAFOperationDef_MonoAudioMixdown"; - if ( aafUIDCmp( auid, &AAFOperationDef_AudioChannelCombiner ) ) return L"AAFOperationDef_AudioChannelCombiner"; - - - static wchar_t TEXTOperationDef[1024]; + return "n/a"; + + if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return "AAFUID_NULL"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoDissolve ) ) return "AAFOperationDef_VideoDissolve"; + if ( aafUIDCmp( auid, &AAFOperationDef_SMPTEVideoWipe ) ) return "AAFOperationDef_SMPTEVideoWipe"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoSpeedControl ) ) return "AAFOperationDef_VideoSpeedControl"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoRepeat ) ) return "AAFOperationDef_VideoRepeat"; + if ( aafUIDCmp( auid, &AAFOperationDef_Flip ) ) return "AAFOperationDef_Flip"; + if ( aafUIDCmp( auid, &AAFOperationDef_Flop ) ) return "AAFOperationDef_Flop"; + if ( aafUIDCmp( auid, &AAFOperationDef_FlipFlop ) ) return "AAFOperationDef_FlipFlop"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoPosition ) ) return "AAFOperationDef_VideoPosition"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoCrop ) ) return "AAFOperationDef_VideoCrop"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoScale ) ) return "AAFOperationDef_VideoScale"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoRotate ) ) return "AAFOperationDef_VideoRotate"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoCornerPinning ) ) return "AAFOperationDef_VideoCornerPinning"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoAlphaWithinVideoKey ) ) return "AAFOperationDef_VideoAlphaWithinVideoKey"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoSeparateAlphaKey ) ) return "AAFOperationDef_VideoSeparateAlphaKey"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoLuminanceKey ) ) return "AAFOperationDef_VideoLuminanceKey"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoChromaKey ) ) return "AAFOperationDef_VideoChromaKey"; + if ( aafUIDCmp( auid, &AAFOperationDef_MonoAudioGain ) ) return "AAFOperationDef_MonoAudioGain"; + if ( aafUIDCmp( auid, &AAFOperationDef_MonoAudioPan ) ) return "AAFOperationDef_MonoAudioPan"; + if ( aafUIDCmp( auid, &AAFOperationDef_MonoAudioDissolve ) ) return "AAFOperationDef_MonoAudioDissolve"; + if ( aafUIDCmp( auid, &AAFOperationDef_TwoParameterMonoAudioDissolve ) ) return "AAFOperationDef_TwoParameterMonoAudioDissolve"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoOpacity ) ) return "AAFOperationDef_VideoOpacity"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoTitle ) ) return "AAFOperationDef_VideoTitle"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoColor ) ) return "AAFOperationDef_VideoColor"; + if ( aafUIDCmp( auid, &AAFOperationDef_Unknown ) ) return "AAFOperationDef_Unknown"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoFadeToBlack ) ) return "AAFOperationDef_VideoFadeToBlack"; + if ( aafUIDCmp( auid, &AAFOperationDef_PictureWithMate ) ) return "AAFOperationDef_PictureWithMate"; + if ( aafUIDCmp( auid, &AAFOperationDef_VideoFrameToMask ) ) return "AAFOperationDef_VideoFrameToMask"; + if ( aafUIDCmp( auid, &AAFOperationDef_StereoAudioDissolve ) ) return "AAFOperationDef_StereoAudioDissolve"; + if ( aafUIDCmp( auid, &AAFOperationDef_StereoAudioGain ) ) return "AAFOperationDef_StereoAudioGain"; + if ( aafUIDCmp( auid, &AAFOperationDef_MonoAudioMixdown ) ) return "AAFOperationDef_MonoAudioMixdown"; + if ( aafUIDCmp( auid, &AAFOperationDef_AudioChannelCombiner ) ) return "AAFOperationDef_AudioChannelCombiner"; + + + static char TEXTOperationDef[1024]; aafObject *OperationDefinitions = aaf_get_propertyValue( aafd->Dictionary, PID_Dictionary_OperationDefinitions, &AAFTypeID_OperationDefinitionStrongReferenceSet ); aafObject *OperationDefinition = NULL; - aaf_foreach_ObjectInSet( &OperationDefinition, OperationDefinitions, NULL ) { + while ( _aaf_foreach_ObjectInSet( &OperationDefinition, OperationDefinitions, NULL ) ) { aafUID_t *OpDefIdent = aaf_get_propertyValue( OperationDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID ); if ( OpDefIdent && aafUIDCmp( OpDefIdent, auid ) ) { - wchar_t *name = aaf_get_propertyValue( OperationDefinition, PID_DefinitionObject_Name, &AAFTypeID_String ); - swprintf( TEXTOperationDef, 1024, L"%" WPRIws, name ); + + char *name = aaf_get_propertyValue( OperationDefinition, PID_DefinitionObject_Name, &AAFTypeID_String ); + + if ( !name ) { + error( "Could not retrieve OperationDefinition::Name" ); + return NULL; + } + + int rc = snprintf( TEXTOperationDef, sizeof(TEXTOperationDef), "%s", name ); + + assert( rc >= 0 && (size_t)rc < sizeof(TEXTOperationDef) ); + + // if ( rc < 0 || (size_t)rc >= 1024 ) { + // fprintf( stderr, "snprintf() error" ); + // return NULL; + // } + free( name ); return TEXTOperationDef; @@ -735,115 +843,130 @@ const wchar_t * aaft_OperationDefToText( AAF_Data *aafd, const aafUID_t *auid ) } - return L"Unknown AAFOperationDef"; + return "Unknown AAFOperationDef"; } -const wchar_t * aaft_InterpolationToText( const aafUID_t *auid ) +const char * aaft_InterpolationToText( const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; + return "n/a"; - if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return L"AAFUID_NULL"; - if ( aafUIDCmp( auid, &AAFInterpolationDef_None ) ) return L"AAFInterpolationDef_None"; - if ( aafUIDCmp( auid, &AAFInterpolationDef_Linear ) ) return L"AAFInterpolationDef_Linear"; - if ( aafUIDCmp( auid, &AAFInterpolationDef_Constant ) ) return L"AAFInterpolationDef_Constant"; - if ( aafUIDCmp( auid, &AAFInterpolationDef_BSpline ) ) return L"AAFInterpolationDef_BSpline"; - if ( aafUIDCmp( auid, &AAFInterpolationDef_Log ) ) return L"AAFInterpolationDef_Log"; - if ( aafUIDCmp( auid, &AAFInterpolationDef_Power ) ) return L"AAFInterpolationDef_Power"; + if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return "AAFUID_NULL"; + if ( aafUIDCmp( auid, &AAFInterpolationDef_None ) ) return "AAFInterpolationDef_None"; + if ( aafUIDCmp( auid, &AAFInterpolationDef_Linear ) ) return "AAFInterpolationDef_Linear"; + if ( aafUIDCmp( auid, &AAFInterpolationDef_Constant ) ) return "AAFInterpolationDef_Constant"; + if ( aafUIDCmp( auid, &AAFInterpolationDef_BSpline ) ) return "AAFInterpolationDef_BSpline"; + if ( aafUIDCmp( auid, &AAFInterpolationDef_Log ) ) return "AAFInterpolationDef_Log"; + if ( aafUIDCmp( auid, &AAFInterpolationDef_Power ) ) return "AAFInterpolationDef_Power"; - return L"Unknown AAFInterpolationDef"; + return "Unknown AAFInterpolationDef"; } -const wchar_t * aaft_ParameterToText( AAF_Data *aafd, const aafUID_t *auid ) +const char * aaft_ParameterToText( AAF_Data *aafd, const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; - - if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return L"AAFUID_NULL"; - if ( aafUIDCmp( auid, &AAFParameterDef_Level ) ) return L"AAFParameterDef_Level"; - if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEWipeNumber ) ) return L"AAFParameterDef_SMPTEWipeNumber"; - if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEReverse ) ) return L"AAFParameterDef_SMPTEReverse"; - if ( aafUIDCmp( auid, &AAFParameterDef_SpeedRatio ) ) return L"AAFParameterDef_SpeedRatio"; - if ( aafUIDCmp( auid, &AAFParameterDef_PositionOffsetX ) ) return L"AAFParameterDef_PositionOffsetX"; - if ( aafUIDCmp( auid, &AAFParameterDef_PositionOffsetY ) ) return L"AAFParameterDef_PositionOffsetY"; - if ( aafUIDCmp( auid, &AAFParameterDef_CropLeft ) ) return L"AAFParameterDef_CropLeft"; - if ( aafUIDCmp( auid, &AAFParameterDef_CropRight ) ) return L"AAFParameterDef_CropRight"; - if ( aafUIDCmp( auid, &AAFParameterDef_CropTop ) ) return L"AAFParameterDef_CropTop"; - if ( aafUIDCmp( auid, &AAFParameterDef_CropBottom ) ) return L"AAFParameterDef_CropBottom"; - if ( aafUIDCmp( auid, &AAFParameterDef_ScaleX ) ) return L"AAFParameterDef_ScaleX"; - if ( aafUIDCmp( auid, &AAFParameterDef_ScaleY ) ) return L"AAFParameterDef_ScaleY"; - if ( aafUIDCmp( auid, &AAFParameterDef_Rotation ) ) return L"AAFParameterDef_Rotation"; - if ( aafUIDCmp( auid, &AAFParameterDef_PinTopLeftX ) ) return L"AAFParameterDef_PinTopLeftX"; - if ( aafUIDCmp( auid, &AAFParameterDef_PinTopLeftY ) ) return L"AAFParameterDef_PinTopLeftY"; - if ( aafUIDCmp( auid, &AAFParameterDef_PinTopRightX ) ) return L"AAFParameterDef_PinTopRightX"; - if ( aafUIDCmp( auid, &AAFParameterDef_PinTopRightY ) ) return L"AAFParameterDef_PinTopRightY"; - if ( aafUIDCmp( auid, &AAFParameterDef_PinBottomLeftX ) ) return L"AAFParameterDef_PinBottomLeftX"; - if ( aafUIDCmp( auid, &AAFParameterDef_PinBottomLeftY ) ) return L"AAFParameterDef_PinBottomLeftY"; - if ( aafUIDCmp( auid, &AAFParameterDef_PinBottomRightX ) ) return L"AAFParameterDef_PinBottomRightX"; - if ( aafUIDCmp( auid, &AAFParameterDef_PinBottomRightY ) ) return L"AAFParameterDef_PinBottomRightY"; - if ( aafUIDCmp( auid, &AAFParameterDef_AlphaKeyInvertAlpha ) ) return L"AAFParameterDef_AlphaKeyInvertAlpha"; - if ( aafUIDCmp( auid, &AAFParameterDef_LumKeyLevel ) ) return L"AAFParameterDef_LumKeyLevel"; - if ( aafUIDCmp( auid, &AAFParameterDef_LumKeyClip ) ) return L"AAFParameterDef_LumKeyClip"; - if ( aafUIDCmp( auid, &AAFParameterDef_Amplitude ) ) return L"AAFParameterDef_Amplitude"; - if ( aafUIDCmp( auid, &AAFParameterDef_Pan ) ) return L"AAFParameterDef_Pan"; - if ( aafUIDCmp( auid, &AAFParameterDef_OutgoingLevel ) ) return L"AAFParameterDef_OutgoingLevel"; - if ( aafUIDCmp( auid, &AAFParameterDef_IncomingLevel ) ) return L"AAFParameterDef_IncomingLevel"; - if ( aafUIDCmp( auid, &AAFParameterDef_OpacityLevel ) ) return L"AAFParameterDef_OpacityLevel"; - if ( aafUIDCmp( auid, &AAFParameterDef_TitleText ) ) return L"AAFParameterDef_TitleText"; - if ( aafUIDCmp( auid, &AAFParameterDef_TitleFontName ) ) return L"AAFParameterDef_TitleFontName"; - if ( aafUIDCmp( auid, &AAFParameterDef_TitleFontSize ) ) return L"AAFParameterDef_TitleFontSize"; - if ( aafUIDCmp( auid, &AAFParameterDef_TitleFontColorR ) ) return L"AAFParameterDef_TitleFontColorR"; - if ( aafUIDCmp( auid, &AAFParameterDef_TitleFontColorG ) ) return L"AAFParameterDef_TitleFontColorG"; - if ( aafUIDCmp( auid, &AAFParameterDef_TitleFontColorB ) ) return L"AAFParameterDef_TitleFontColorB"; - if ( aafUIDCmp( auid, &AAFParameterDef_TitleAlignment ) ) return L"AAFParameterDef_TitleAlignment"; - if ( aafUIDCmp( auid, &AAFParameterDef_TitleBold ) ) return L"AAFParameterDef_TitleBold"; - if ( aafUIDCmp( auid, &AAFParameterDef_TitleItalic ) ) return L"AAFParameterDef_TitleItalic"; - if ( aafUIDCmp( auid, &AAFParameterDef_TitlePositionX ) ) return L"AAFParameterDef_TitlePositionX"; - if ( aafUIDCmp( auid, &AAFParameterDef_TitlePositionY ) ) return L"AAFParameterDef_TitlePositionY"; - if ( aafUIDCmp( auid, &AAFParameterDef_ColorSlopeR ) ) return L"AAFParameterDef_ColorSlopeR"; - if ( aafUIDCmp( auid, &AAFParameterDef_ColorSlopeG ) ) return L"AAFParameterDef_ColorSlopeG"; - if ( aafUIDCmp( auid, &AAFParameterDef_ColorSlopeB ) ) return L"AAFParameterDef_ColorSlopeB"; - if ( aafUIDCmp( auid, &AAFParameterDef_ColorOffsetR ) ) return L"AAFParameterDef_ColorOffsetR"; - if ( aafUIDCmp( auid, &AAFParameterDef_ColorOffsetG ) ) return L"AAFParameterDef_ColorOffsetG"; - if ( aafUIDCmp( auid, &AAFParameterDef_ColorOffsetB ) ) return L"AAFParameterDef_ColorOffsetB"; - if ( aafUIDCmp( auid, &AAFParameterDef_ColorPowerR ) ) return L"AAFParameterDef_ColorPowerR"; - if ( aafUIDCmp( auid, &AAFParameterDef_ColorPowerG ) ) return L"AAFParameterDef_ColorPowerG"; - if ( aafUIDCmp( auid, &AAFParameterDef_ColorPowerB ) ) return L"AAFParameterDef_ColorPowerB"; - if ( aafUIDCmp( auid, &AAFParameterDef_ColorSaturation ) ) return L"AAFParameterDef_ColorSaturation"; - if ( aafUIDCmp( auid, &AAFParameterDef_ColorCorrectionDescription ) ) return L"AAFParameterDef_ColorCorrectionDescription"; - if ( aafUIDCmp( auid, &AAFParameterDef_ColorInputDescription ) ) return L"AAFParameterDef_ColorInputDescription"; - if ( aafUIDCmp( auid, &AAFParameterDef_ColorViewingDescription ) ) return L"AAFParameterDef_ColorViewingDescription"; - if ( aafUIDCmp( auid, &AAFParameterDef_SMPTESoft ) ) return L"AAFParameterDef_SMPTESoft"; - if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEBorder ) ) return L"AAFParameterDef_SMPTEBorder"; - if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEPosition ) ) return L"AAFParameterDef_SMPTEPosition"; - if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEModulator ) ) return L"AAFParameterDef_SMPTEModulator"; - if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEShadow ) ) return L"AAFParameterDef_SMPTEShadow"; - if ( aafUIDCmp( auid, &AAFParameterDef_SMPTETumble ) ) return L"AAFParameterDef_SMPTETumble"; - if ( aafUIDCmp( auid, &AAFParameterDef_SMPTESpotlight ) ) return L"AAFParameterDef_SMPTESpotlight"; - if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEReplicationH ) ) return L"AAFParameterDef_SMPTEReplicationH"; - if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEReplicationV ) ) return L"AAFParameterDef_SMPTEReplicationV"; - if ( aafUIDCmp( auid, &AAFParameterDef_SMPTECheckerboard ) ) return L"AAFParameterDef_SMPTECheckerboard"; - if ( aafUIDCmp( auid, &AAFParameterDef_PhaseOffset ) ) return L"AAFParameterDef_PhaseOffset"; + return "n/a"; + + if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return "AAFUID_NULL"; + if ( aafUIDCmp( auid, &AAFParameterDef_Level ) ) return "AAFParameterDef_Level"; + if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEWipeNumber ) ) return "AAFParameterDef_SMPTEWipeNumber"; + if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEReverse ) ) return "AAFParameterDef_SMPTEReverse"; + if ( aafUIDCmp( auid, &AAFParameterDef_SpeedRatio ) ) return "AAFParameterDef_SpeedRatio"; + if ( aafUIDCmp( auid, &AAFParameterDef_PositionOffsetX ) ) return "AAFParameterDef_PositionOffsetX"; + if ( aafUIDCmp( auid, &AAFParameterDef_PositionOffsetY ) ) return "AAFParameterDef_PositionOffsetY"; + if ( aafUIDCmp( auid, &AAFParameterDef_CropLeft ) ) return "AAFParameterDef_CropLeft"; + if ( aafUIDCmp( auid, &AAFParameterDef_CropRight ) ) return "AAFParameterDef_CropRight"; + if ( aafUIDCmp( auid, &AAFParameterDef_CropTop ) ) return "AAFParameterDef_CropTop"; + if ( aafUIDCmp( auid, &AAFParameterDef_CropBottom ) ) return "AAFParameterDef_CropBottom"; + if ( aafUIDCmp( auid, &AAFParameterDef_ScaleX ) ) return "AAFParameterDef_ScaleX"; + if ( aafUIDCmp( auid, &AAFParameterDef_ScaleY ) ) return "AAFParameterDef_ScaleY"; + if ( aafUIDCmp( auid, &AAFParameterDef_Rotation ) ) return "AAFParameterDef_Rotation"; + if ( aafUIDCmp( auid, &AAFParameterDef_PinTopLeftX ) ) return "AAFParameterDef_PinTopLeftX"; + if ( aafUIDCmp( auid, &AAFParameterDef_PinTopLeftY ) ) return "AAFParameterDef_PinTopLeftY"; + if ( aafUIDCmp( auid, &AAFParameterDef_PinTopRightX ) ) return "AAFParameterDef_PinTopRightX"; + if ( aafUIDCmp( auid, &AAFParameterDef_PinTopRightY ) ) return "AAFParameterDef_PinTopRightY"; + if ( aafUIDCmp( auid, &AAFParameterDef_PinBottomLeftX ) ) return "AAFParameterDef_PinBottomLeftX"; + if ( aafUIDCmp( auid, &AAFParameterDef_PinBottomLeftY ) ) return "AAFParameterDef_PinBottomLeftY"; + if ( aafUIDCmp( auid, &AAFParameterDef_PinBottomRightX ) ) return "AAFParameterDef_PinBottomRightX"; + if ( aafUIDCmp( auid, &AAFParameterDef_PinBottomRightY ) ) return "AAFParameterDef_PinBottomRightY"; + if ( aafUIDCmp( auid, &AAFParameterDef_AlphaKeyInvertAlpha ) ) return "AAFParameterDef_AlphaKeyInvertAlpha"; + if ( aafUIDCmp( auid, &AAFParameterDef_LumKeyLevel ) ) return "AAFParameterDef_LumKeyLevel"; + if ( aafUIDCmp( auid, &AAFParameterDef_LumKeyClip ) ) return "AAFParameterDef_LumKeyClip"; + if ( aafUIDCmp( auid, &AAFParameterDef_Amplitude ) ) return "AAFParameterDef_Amplitude"; + if ( aafUIDCmp( auid, &AAFParameterDef_Pan ) ) return "AAFParameterDef_Pan"; + if ( aafUIDCmp( auid, &AAFParameterDef_OutgoingLevel ) ) return "AAFParameterDef_OutgoingLevel"; + if ( aafUIDCmp( auid, &AAFParameterDef_IncomingLevel ) ) return "AAFParameterDef_IncomingLevel"; + if ( aafUIDCmp( auid, &AAFParameterDef_OpacityLevel ) ) return "AAFParameterDef_OpacityLevel"; + if ( aafUIDCmp( auid, &AAFParameterDef_TitleText ) ) return "AAFParameterDef_TitleText"; + if ( aafUIDCmp( auid, &AAFParameterDef_TitleFontName ) ) return "AAFParameterDef_TitleFontName"; + if ( aafUIDCmp( auid, &AAFParameterDef_TitleFontSize ) ) return "AAFParameterDef_TitleFontSize"; + if ( aafUIDCmp( auid, &AAFParameterDef_TitleFontColorR ) ) return "AAFParameterDef_TitleFontColorR"; + if ( aafUIDCmp( auid, &AAFParameterDef_TitleFontColorG ) ) return "AAFParameterDef_TitleFontColorG"; + if ( aafUIDCmp( auid, &AAFParameterDef_TitleFontColorB ) ) return "AAFParameterDef_TitleFontColorB"; + if ( aafUIDCmp( auid, &AAFParameterDef_TitleAlignment ) ) return "AAFParameterDef_TitleAlignment"; + if ( aafUIDCmp( auid, &AAFParameterDef_TitleBold ) ) return "AAFParameterDef_TitleBold"; + if ( aafUIDCmp( auid, &AAFParameterDef_TitleItalic ) ) return "AAFParameterDef_TitleItalic"; + if ( aafUIDCmp( auid, &AAFParameterDef_TitlePositionX ) ) return "AAFParameterDef_TitlePositionX"; + if ( aafUIDCmp( auid, &AAFParameterDef_TitlePositionY ) ) return "AAFParameterDef_TitlePositionY"; + if ( aafUIDCmp( auid, &AAFParameterDef_ColorSlopeR ) ) return "AAFParameterDef_ColorSlopeR"; + if ( aafUIDCmp( auid, &AAFParameterDef_ColorSlopeG ) ) return "AAFParameterDef_ColorSlopeG"; + if ( aafUIDCmp( auid, &AAFParameterDef_ColorSlopeB ) ) return "AAFParameterDef_ColorSlopeB"; + if ( aafUIDCmp( auid, &AAFParameterDef_ColorOffsetR ) ) return "AAFParameterDef_ColorOffsetR"; + if ( aafUIDCmp( auid, &AAFParameterDef_ColorOffsetG ) ) return "AAFParameterDef_ColorOffsetG"; + if ( aafUIDCmp( auid, &AAFParameterDef_ColorOffsetB ) ) return "AAFParameterDef_ColorOffsetB"; + if ( aafUIDCmp( auid, &AAFParameterDef_ColorPowerR ) ) return "AAFParameterDef_ColorPowerR"; + if ( aafUIDCmp( auid, &AAFParameterDef_ColorPowerG ) ) return "AAFParameterDef_ColorPowerG"; + if ( aafUIDCmp( auid, &AAFParameterDef_ColorPowerB ) ) return "AAFParameterDef_ColorPowerB"; + if ( aafUIDCmp( auid, &AAFParameterDef_ColorSaturation ) ) return "AAFParameterDef_ColorSaturation"; + if ( aafUIDCmp( auid, &AAFParameterDef_ColorCorrectionDescription ) ) return "AAFParameterDef_ColorCorrectionDescription"; + if ( aafUIDCmp( auid, &AAFParameterDef_ColorInputDescription ) ) return "AAFParameterDef_ColorInputDescription"; + if ( aafUIDCmp( auid, &AAFParameterDef_ColorViewingDescription ) ) return "AAFParameterDef_ColorViewingDescription"; + if ( aafUIDCmp( auid, &AAFParameterDef_SMPTESoft ) ) return "AAFParameterDef_SMPTESoft"; + if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEBorder ) ) return "AAFParameterDef_SMPTEBorder"; + if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEPosition ) ) return "AAFParameterDef_SMPTEPosition"; + if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEModulator ) ) return "AAFParameterDef_SMPTEModulator"; + if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEShadow ) ) return "AAFParameterDef_SMPTEShadow"; + if ( aafUIDCmp( auid, &AAFParameterDef_SMPTETumble ) ) return "AAFParameterDef_SMPTETumble"; + if ( aafUIDCmp( auid, &AAFParameterDef_SMPTESpotlight ) ) return "AAFParameterDef_SMPTESpotlight"; + if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEReplicationH ) ) return "AAFParameterDef_SMPTEReplicationH"; + if ( aafUIDCmp( auid, &AAFParameterDef_SMPTEReplicationV ) ) return "AAFParameterDef_SMPTEReplicationV"; + if ( aafUIDCmp( auid, &AAFParameterDef_SMPTECheckerboard ) ) return "AAFParameterDef_SMPTECheckerboard"; + if ( aafUIDCmp( auid, &AAFParameterDef_PhaseOffset ) ) return "AAFParameterDef_PhaseOffset"; /* NOTE: Seen in Avid MC and PT files : PanVol_IsTrimGainEffect */ - static wchar_t TEXTParameterDef[1024]; + static char TEXTParameterDef[1024]; aafObject *ParameterDefinitions = aaf_get_propertyValue( aafd->Dictionary, PID_Dictionary_ParameterDefinitions, &AAFTypeID_ParameterDefinitionStrongReferenceSet ); aafObject *ParameterDefinition = NULL; - aaf_foreach_ObjectInSet( &ParameterDefinition, ParameterDefinitions, NULL ) { + while ( _aaf_foreach_ObjectInSet( &ParameterDefinition, ParameterDefinitions, NULL ) ) { aafUID_t *ParamDefIdent = aaf_get_propertyValue( ParameterDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID ); if ( ParamDefIdent && aafUIDCmp( ParamDefIdent, auid ) ) { - wchar_t *name = aaf_get_propertyValue( ParameterDefinition, PID_DefinitionObject_Name, &AAFTypeID_String ); - swprintf( TEXTParameterDef, 1024, L"%" WPRIws, name ); + + char *name = aaf_get_propertyValue( ParameterDefinition, PID_DefinitionObject_Name, &AAFTypeID_String ); + + if ( !name ) { + error( "Could not retrieve ParameterDefinition::Name" ); + return NULL; + } + + int rc = snprintf( TEXTParameterDef, sizeof(TEXTParameterDef), "%s", name ); + + assert( rc >= 0 && (size_t)rc < sizeof(TEXTParameterDef) ); + + // if ( rc < 0 || (size_t)rc >= 1024 ) { + // fprintf( stderr, "snprintf() error" ); + // return NULL; + // } + free( name ); return TEXTParameterDef; @@ -851,362 +974,362 @@ const wchar_t * aaft_ParameterToText( AAF_Data *aafd, const aafUID_t *auid ) } - return L"Unknown AAFParameterDef"; + return "Unknown AAFParameterDef"; } -const wchar_t * aaft_TransferCharacteristicToText( const aafUID_t *auid ) +const char * aaft_TransferCharacteristicToText( const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; + return "n/a"; - if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return L"AAFUID_NULL"; - if ( aafUIDCmp( auid, &AAFTransferCharacteristic_ITU470_PAL ) ) return L"AAFTransferCharacteristic_ITU470_PAL"; - if ( aafUIDCmp( auid, &AAFTransferCharacteristic_ITU709 ) ) return L"AAFTransferCharacteristic_ITU709"; - if ( aafUIDCmp( auid, &AAFTransferCharacteristic_SMPTE240M ) ) return L"AAFTransferCharacteristic_SMPTE240M"; - if ( aafUIDCmp( auid, &AAFTransferCharacteristic_274M_296M ) ) return L"AAFTransferCharacteristic_274M_296M"; - if ( aafUIDCmp( auid, &AAFTransferCharacteristic_ITU1361 ) ) return L"AAFTransferCharacteristic_ITU1361"; - if ( aafUIDCmp( auid, &AAFTransferCharacteristic_linear ) ) return L"AAFTransferCharacteristic_linear"; + if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return "AAFUID_NULL"; + if ( aafUIDCmp( auid, &AAFTransferCharacteristic_ITU470_PAL ) ) return "AAFTransferCharacteristic_ITU470_PAL"; + if ( aafUIDCmp( auid, &AAFTransferCharacteristic_ITU709 ) ) return "AAFTransferCharacteristic_ITU709"; + if ( aafUIDCmp( auid, &AAFTransferCharacteristic_SMPTE240M ) ) return "AAFTransferCharacteristic_SMPTE240M"; + if ( aafUIDCmp( auid, &AAFTransferCharacteristic_274M_296M ) ) return "AAFTransferCharacteristic_274M_296M"; + if ( aafUIDCmp( auid, &AAFTransferCharacteristic_ITU1361 ) ) return "AAFTransferCharacteristic_ITU1361"; + if ( aafUIDCmp( auid, &AAFTransferCharacteristic_linear ) ) return "AAFTransferCharacteristic_linear"; - return L"Unknown AAFTransferCharacteristic"; + return "Unknown AAFTransferCharacteristic"; } -const wchar_t * aaft_CodingEquationsToText( const aafUID_t *auid ) +const char * aaft_CodingEquationsToText( const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; + return "n/a"; - if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return L"AAFUID_NULL"; - if ( aafUIDCmp( auid, &AAFCodingEquations_ITU601 ) ) return L"AAFCodingEquations_ITU601"; - if ( aafUIDCmp( auid, &AAFCodingEquations_ITU709 ) ) return L"AAFCodingEquations_ITU709"; - if ( aafUIDCmp( auid, &AAFCodingEquations_SMPTE240M ) ) return L"AAFCodingEquations_SMPTE240M"; + if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return "AAFUID_NULL"; + if ( aafUIDCmp( auid, &AAFCodingEquations_ITU601 ) ) return "AAFCodingEquations_ITU601"; + if ( aafUIDCmp( auid, &AAFCodingEquations_ITU709 ) ) return "AAFCodingEquations_ITU709"; + if ( aafUIDCmp( auid, &AAFCodingEquations_SMPTE240M ) ) return "AAFCodingEquations_SMPTE240M"; - return L"Unknown AAFCodingEquations"; + return "Unknown AAFCodingEquations"; } -const wchar_t * aaft_ColorPrimariesToText( const aafUID_t *auid ) +const char * aaft_ColorPrimariesToText( const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; + return "n/a"; - if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return L"AAFUID_NULL"; - if ( aafUIDCmp( auid, &AAFColorPrimaries_SMPTE170M ) ) return L"AAFColorPrimaries_SMPTE170M"; - if ( aafUIDCmp( auid, &AAFColorPrimaries_ITU470_PAL ) ) return L"AAFColorPrimaries_ITU470_PAL"; - if ( aafUIDCmp( auid, &AAFColorPrimaries_ITU709 ) ) return L"AAFColorPrimaries_ITU709"; + if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return "AAFUID_NULL"; + if ( aafUIDCmp( auid, &AAFColorPrimaries_SMPTE170M ) ) return "AAFColorPrimaries_SMPTE170M"; + if ( aafUIDCmp( auid, &AAFColorPrimaries_ITU470_PAL ) ) return "AAFColorPrimaries_ITU470_PAL"; + if ( aafUIDCmp( auid, &AAFColorPrimaries_ITU709 ) ) return "AAFColorPrimaries_ITU709"; - return L"Unknown AAFColorPrimaries"; + return "Unknown AAFColorPrimaries"; } -const wchar_t * aaft_UsageCodeToText( const aafUID_t *auid ) +const char * aaft_UsageCodeToText( const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; + return "n/a"; - if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return L"AAFUID_NULL"; - if ( aafUIDCmp( auid, &AAFUsage_SubClip ) ) return L"AAFUsage_SubClip"; - if ( aafUIDCmp( auid, &AAFUsage_AdjustedClip ) ) return L"AAFUsage_AdjustedClip"; - if ( aafUIDCmp( auid, &AAFUsage_TopLevel ) ) return L"AAFUsage_TopLevel"; - if ( aafUIDCmp( auid, &AAFUsage_LowerLevel ) ) return L"AAFUsage_LowerLevel"; - if ( aafUIDCmp( auid, &AAFUsage_Template ) ) return L"AAFUsage_Template"; + if ( aafUIDCmp( auid, &AAFUID_NULL ) ) return "AAFUID_NULL"; + if ( aafUIDCmp( auid, &AAFUsage_SubClip ) ) return "AAFUsage_SubClip"; + if ( aafUIDCmp( auid, &AAFUsage_AdjustedClip ) ) return "AAFUsage_AdjustedClip"; + if ( aafUIDCmp( auid, &AAFUsage_TopLevel ) ) return "AAFUsage_TopLevel"; + if ( aafUIDCmp( auid, &AAFUsage_LowerLevel ) ) return "AAFUsage_LowerLevel"; + if ( aafUIDCmp( auid, &AAFUsage_Template ) ) return "AAFUsage_Template"; - return L"Unknown AAFUsage"; + return "Unknown AAFUsage"; } -const wchar_t * aaft_PIDToText( AAF_Data *aafd, aafPID_t pid ) +const char * aaft_PIDToText( AAF_Data *aafd, aafPID_t pid ) { switch ( pid ) { - case PID_Root_MetaDictionary: return L"PID_Root_MetaDictionary"; - case PID_Root_Header: return L"PID_Root_Header"; - case PID_InterchangeObject_ObjClass: return L"PID_InterchangeObject_ObjClass"; - case PID_InterchangeObject_Generation: return L"PID_InterchangeObject_Generation"; - case PID_Component_DataDefinition: return L"PID_Component_DataDefinition"; - case PID_Component_Length: return L"PID_Component_Length"; - case PID_Component_KLVData: return L"PID_Component_KLVData"; - case PID_Component_UserComments: return L"PID_Component_UserComments"; - case PID_Component_Attributes: return L"PID_Component_Attributes"; - case PID_EdgeCode_Start: return L"PID_EdgeCode_Start"; - case PID_EdgeCode_FilmKind: return L"PID_EdgeCode_FilmKind"; - case PID_EdgeCode_CodeFormat: return L"PID_EdgeCode_CodeFormat"; - case PID_EdgeCode_Header: return L"PID_EdgeCode_Header"; - case PID_EssenceGroup_Choices: return L"PID_EssenceGroup_Choices"; - case PID_EssenceGroup_StillFrame: return L"PID_EssenceGroup_StillFrame"; - case PID_Event_Position: return L"PID_Event_Position"; - case PID_Event_Comment: return L"PID_Event_Comment"; - case PID_GPITrigger_ActiveState: return L"PID_GPITrigger_ActiveState"; - case PID_CommentMarker_Annotation: return L"PID_CommentMarker_Annotation"; - case PID_OperationGroup_Operation: return L"PID_OperationGroup_Operation"; - case PID_OperationGroup_InputSegments: return L"PID_OperationGroup_InputSegments"; - case PID_OperationGroup_Parameters: return L"PID_OperationGroup_Parameters"; - case PID_OperationGroup_BypassOverride: return L"PID_OperationGroup_BypassOverride"; - case PID_OperationGroup_Rendering: return L"PID_OperationGroup_Rendering"; - case PID_NestedScope_Slots: return L"PID_NestedScope_Slots"; - case PID_Pulldown_InputSegment: return L"PID_Pulldown_InputSegment"; - case PID_Pulldown_PulldownKind: return L"PID_Pulldown_PulldownKind"; - case PID_Pulldown_PulldownDirection: return L"PID_Pulldown_PulldownDirection"; - case PID_Pulldown_PhaseFrame: return L"PID_Pulldown_PhaseFrame"; - case PID_ScopeReference_RelativeScope: return L"PID_ScopeReference_RelativeScope"; - case PID_ScopeReference_RelativeSlot: return L"PID_ScopeReference_RelativeSlot"; - case PID_Selector_Selected: return L"PID_Selector_Selected"; - case PID_Selector_Alternates: return L"PID_Selector_Alternates"; - case PID_Sequence_Components: return L"PID_Sequence_Components"; - case PID_SourceReference_SourceID: return L"PID_SourceReference_SourceID"; - case PID_SourceReference_SourceMobSlotID: return L"PID_SourceReference_SourceMobSlotID"; - case PID_SourceReference_ChannelIDs: return L"PID_SourceReference_ChannelIDs"; - case PID_SourceReference_MonoSourceSlotIDs: return L"PID_SourceReference_MonoSourceSlotIDs"; - case PID_SourceClip_StartTime: return L"PID_SourceClip_StartTime"; - case PID_SourceClip_FadeInLength: return L"PID_SourceClip_FadeInLength"; - case PID_SourceClip_FadeInType: return L"PID_SourceClip_FadeInType"; - case PID_SourceClip_FadeOutLength: return L"PID_SourceClip_FadeOutLength"; - case PID_SourceClip_FadeOutType: return L"PID_SourceClip_FadeOutType"; - case PID_HTMLClip_BeginAnchor: return L"PID_HTMLClip_BeginAnchor"; - case PID_HTMLClip_EndAnchor: return L"PID_HTMLClip_EndAnchor"; - case PID_Timecode_Start: return L"PID_Timecode_Start"; - case PID_Timecode_FPS: return L"PID_Timecode_FPS"; - case PID_Timecode_Drop: return L"PID_Timecode_Drop"; - case PID_TimecodeStream_SampleRate: return L"PID_TimecodeStream_SampleRate"; - case PID_TimecodeStream_Source: return L"PID_TimecodeStream_Source"; - case PID_TimecodeStream_SourceType: return L"PID_TimecodeStream_SourceType"; - case PID_TimecodeStream12M_IncludeSync: return L"PID_TimecodeStream12M_IncludeSync"; - case PID_Transition_OperationGroup: return L"PID_Transition_OperationGroup"; - case PID_Transition_CutPoint: return L"PID_Transition_CutPoint"; - case PID_ContentStorage_Mobs: return L"PID_ContentStorage_Mobs"; - case PID_ContentStorage_EssenceData: return L"PID_ContentStorage_EssenceData"; - case PID_ControlPoint_Value: return L"PID_ControlPoint_Value"; - case PID_ControlPoint_Time: return L"PID_ControlPoint_Time"; - case PID_ControlPoint_EditHint: return L"PID_ControlPoint_EditHint"; - case PID_DefinitionObject_Identification: return L"PID_DefinitionObject_Identification"; - case PID_DefinitionObject_Name: return L"PID_DefinitionObject_Name"; - case PID_DefinitionObject_Description: return L"PID_DefinitionObject_Description"; - case PID_OperationDefinition_DataDefinition: return L"PID_OperationDefinition_DataDefinition"; - case PID_OperationDefinition_IsTimeWarp: return L"PID_OperationDefinition_IsTimeWarp"; - case PID_OperationDefinition_DegradeTo: return L"PID_OperationDefinition_DegradeTo"; - case PID_OperationDefinition_OperationCategory: return L"PID_OperationDefinition_OperationCategory"; - case PID_OperationDefinition_NumberInputs: return L"PID_OperationDefinition_NumberInputs"; - case PID_OperationDefinition_Bypass: return L"PID_OperationDefinition_Bypass"; - case PID_OperationDefinition_ParametersDefined: return L"PID_OperationDefinition_ParametersDefined"; - case PID_ParameterDefinition_Type: return L"PID_ParameterDefinition_Type"; - case PID_ParameterDefinition_DisplayUnits: return L"PID_ParameterDefinition_DisplayUnits"; - case PID_PluginDefinition_PluginCategory: return L"PID_PluginDefinition_PluginCategory"; - case PID_PluginDefinition_VersionNumber: return L"PID_PluginDefinition_VersionNumber"; - case PID_PluginDefinition_VersionString: return L"PID_PluginDefinition_VersionString"; - case PID_PluginDefinition_Manufacturer: return L"PID_PluginDefinition_Manufacturer"; - case PID_PluginDefinition_ManufacturerInfo: return L"PID_PluginDefinition_ManufacturerInfo"; - case PID_PluginDefinition_ManufacturerID: return L"PID_PluginDefinition_ManufacturerID"; - case PID_PluginDefinition_Platform: return L"PID_PluginDefinition_Platform"; - case PID_PluginDefinition_MinPlatformVersion: return L"PID_PluginDefinition_MinPlatformVersion"; - case PID_PluginDefinition_MaxPlatformVersion: return L"PID_PluginDefinition_MaxPlatformVersion"; - case PID_PluginDefinition_Engine: return L"PID_PluginDefinition_Engine"; - case PID_PluginDefinition_MinEngineVersion: return L"PID_PluginDefinition_MinEngineVersion"; - case PID_PluginDefinition_MaxEngineVersion: return L"PID_PluginDefinition_MaxEngineVersion"; - case PID_PluginDefinition_PluginAPI: return L"PID_PluginDefinition_PluginAPI"; - case PID_PluginDefinition_MinPluginAPI: return L"PID_PluginDefinition_MinPluginAPI"; - case PID_PluginDefinition_MaxPluginAPI: return L"PID_PluginDefinition_MaxPluginAPI"; - case PID_PluginDefinition_SoftwareOnly: return L"PID_PluginDefinition_SoftwareOnly"; - case PID_PluginDefinition_Accelerator: return L"PID_PluginDefinition_Accelerator"; - case PID_PluginDefinition_Locators: return L"PID_PluginDefinition_Locators"; - case PID_PluginDefinition_Authentication: return L"PID_PluginDefinition_Authentication"; - case PID_PluginDefinition_DefinitionObject: return L"PID_PluginDefinition_DefinitionObject"; - case PID_CodecDefinition_FileDescriptorClass: return L"PID_CodecDefinition_FileDescriptorClass"; - case PID_CodecDefinition_DataDefinitions: return L"PID_CodecDefinition_DataDefinitions"; - case PID_ContainerDefinition_EssenceIsIdentified: return L"PID_ContainerDefinition_EssenceIsIdentified"; - case PID_Dictionary_OperationDefinitions: return L"PID_Dictionary_OperationDefinitions"; - case PID_Dictionary_ParameterDefinitions: return L"PID_Dictionary_ParameterDefinitions"; - case PID_Dictionary_DataDefinitions: return L"PID_Dictionary_DataDefinitions"; - case PID_Dictionary_PluginDefinitions: return L"PID_Dictionary_PluginDefinitions"; - case PID_Dictionary_CodecDefinitions: return L"PID_Dictionary_CodecDefinitions"; - case PID_Dictionary_ContainerDefinitions: return L"PID_Dictionary_ContainerDefinitions"; - case PID_Dictionary_InterpolationDefinitions: return L"PID_Dictionary_InterpolationDefinitions"; - case PID_Dictionary_KLVDataDefinitions: return L"PID_Dictionary_KLVDataDefinitions"; - case PID_Dictionary_TaggedValueDefinitions: return L"PID_Dictionary_TaggedValueDefinitions"; - case PID_EssenceData_MobID: return L"PID_EssenceData_MobID"; - case PID_EssenceData_Data: return L"PID_EssenceData_Data"; - case PID_EssenceData_SampleIndex: return L"PID_EssenceData_SampleIndex"; - case PID_EssenceDescriptor_Locator: return L"PID_EssenceDescriptor_Locator"; - case PID_FileDescriptor_SampleRate: return L"PID_FileDescriptor_SampleRate"; - case PID_FileDescriptor_Length: return L"PID_FileDescriptor_Length"; - case PID_FileDescriptor_ContainerFormat: return L"PID_FileDescriptor_ContainerFormat"; - case PID_FileDescriptor_CodecDefinition: return L"PID_FileDescriptor_CodecDefinition"; - case PID_FileDescriptor_LinkedSlotID: return L"PID_FileDescriptor_LinkedSlotID"; - case PID_AIFCDescriptor_Summary: return L"PID_AIFCDescriptor_Summary"; - case PID_DigitalImageDescriptor_Compression: return L"PID_DigitalImageDescriptor_Compression"; - case PID_DigitalImageDescriptor_StoredHeight: return L"PID_DigitalImageDescriptor_StoredHeight"; - case PID_DigitalImageDescriptor_StoredWidth: return L"PID_DigitalImageDescriptor_StoredWidth"; - case PID_DigitalImageDescriptor_SampledHeight: return L"PID_DigitalImageDescriptor_SampledHeight"; - case PID_DigitalImageDescriptor_SampledWidth: return L"PID_DigitalImageDescriptor_SampledWidth"; - case PID_DigitalImageDescriptor_SampledXOffset: return L"PID_DigitalImageDescriptor_SampledXOffset"; - case PID_DigitalImageDescriptor_SampledYOffset: return L"PID_DigitalImageDescriptor_SampledYOffset"; - case PID_DigitalImageDescriptor_DisplayHeight: return L"PID_DigitalImageDescriptor_DisplayHeight"; - case PID_DigitalImageDescriptor_DisplayWidth: return L"PID_DigitalImageDescriptor_DisplayWidth"; - case PID_DigitalImageDescriptor_DisplayXOffset: return L"PID_DigitalImageDescriptor_DisplayXOffset"; - case PID_DigitalImageDescriptor_DisplayYOffset: return L"PID_DigitalImageDescriptor_DisplayYOffset"; - case PID_DigitalImageDescriptor_FrameLayout: return L"PID_DigitalImageDescriptor_FrameLayout"; - case PID_DigitalImageDescriptor_VideoLineMap: return L"PID_DigitalImageDescriptor_VideoLineMap"; - case PID_DigitalImageDescriptor_ImageAspectRatio: return L"PID_DigitalImageDescriptor_ImageAspectRatio"; - case PID_DigitalImageDescriptor_AlphaTransparency: return L"PID_DigitalImageDescriptor_AlphaTransparency"; - case PID_DigitalImageDescriptor_TransferCharacteristic: return L"PID_DigitalImageDescriptor_TransferCharacteristic"; - case PID_DigitalImageDescriptor_ColorPrimaries: return L"PID_DigitalImageDescriptor_ColorPrimaries"; - case PID_DigitalImageDescriptor_CodingEquations: return L"PID_DigitalImageDescriptor_CodingEquations"; - case PID_DigitalImageDescriptor_ImageAlignmentFactor: return L"PID_DigitalImageDescriptor_ImageAlignmentFactor"; - case PID_DigitalImageDescriptor_FieldDominance: return L"PID_DigitalImageDescriptor_FieldDominance"; - case PID_DigitalImageDescriptor_FieldStartOffset: return L"PID_DigitalImageDescriptor_FieldStartOffset"; - case PID_DigitalImageDescriptor_FieldEndOffset: return L"PID_DigitalImageDescriptor_FieldEndOffset"; - case PID_DigitalImageDescriptor_SignalStandard: return L"PID_DigitalImageDescriptor_SignalStandard"; - case PID_DigitalImageDescriptor_StoredF2Offset: return L"PID_DigitalImageDescriptor_StoredF2Offset"; - case PID_DigitalImageDescriptor_DisplayF2Offset: return L"PID_DigitalImageDescriptor_DisplayF2Offset"; - case PID_DigitalImageDescriptor_ActiveFormatDescriptor: return L"PID_DigitalImageDescriptor_ActiveFormatDescriptor"; - case PID_CDCIDescriptor_ComponentWidth: return L"PID_CDCIDescriptor_ComponentWidth"; - case PID_CDCIDescriptor_HorizontalSubsampling: return L"PID_CDCIDescriptor_HorizontalSubsampling"; - case PID_CDCIDescriptor_ColorSiting: return L"PID_CDCIDescriptor_ColorSiting"; - case PID_CDCIDescriptor_BlackReferenceLevel: return L"PID_CDCIDescriptor_BlackReferenceLevel"; - case PID_CDCIDescriptor_WhiteReferenceLevel: return L"PID_CDCIDescriptor_WhiteReferenceLevel"; - case PID_CDCIDescriptor_ColorRange: return L"PID_CDCIDescriptor_ColorRange"; - case PID_CDCIDescriptor_PaddingBits: return L"PID_CDCIDescriptor_PaddingBits"; - case PID_CDCIDescriptor_VerticalSubsampling: return L"PID_CDCIDescriptor_VerticalSubsampling"; - case PID_CDCIDescriptor_AlphaSamplingWidth: return L"PID_CDCIDescriptor_AlphaSamplingWidth"; - case PID_CDCIDescriptor_ReversedByteOrder: return L"PID_CDCIDescriptor_ReversedByteOrder"; - case PID_RGBADescriptor_PixelLayout: return L"PID_RGBADescriptor_PixelLayout"; - case PID_RGBADescriptor_Palette: return L"PID_RGBADescriptor_Palette"; - case PID_RGBADescriptor_PaletteLayout: return L"PID_RGBADescriptor_PaletteLayout"; - case PID_RGBADescriptor_ScanningDirection: return L"PID_RGBADescriptor_ScanningDirection"; - case PID_RGBADescriptor_ComponentMaxRef: return L"PID_RGBADescriptor_ComponentMaxRef"; - case PID_RGBADescriptor_ComponentMinRef: return L"PID_RGBADescriptor_ComponentMinRef"; - case PID_RGBADescriptor_AlphaMaxRef: return L"PID_RGBADescriptor_AlphaMaxRef"; - case PID_RGBADescriptor_AlphaMinRef: return L"PID_RGBADescriptor_AlphaMinRef"; - case PID_TIFFDescriptor_IsUniform: return L"PID_TIFFDescriptor_IsUniform"; - case PID_TIFFDescriptor_IsContiguous: return L"PID_TIFFDescriptor_IsContiguous"; - case PID_TIFFDescriptor_LeadingLines: return L"PID_TIFFDescriptor_LeadingLines"; - case PID_TIFFDescriptor_TrailingLines: return L"PID_TIFFDescriptor_TrailingLines"; - case PID_TIFFDescriptor_JPEGTableID: return L"PID_TIFFDescriptor_JPEGTableID"; - case PID_TIFFDescriptor_Summary: return L"PID_TIFFDescriptor_Summary"; - case PID_WAVEDescriptor_Summary: return L"PID_WAVEDescriptor_Summary"; - case PID_FilmDescriptor_FilmFormat: return L"PID_FilmDescriptor_FilmFormat"; - case PID_FilmDescriptor_FrameRate: return L"PID_FilmDescriptor_FrameRate"; - case PID_FilmDescriptor_PerforationsPerFrame: return L"PID_FilmDescriptor_PerforationsPerFrame"; - case PID_FilmDescriptor_FilmAspectRatio: return L"PID_FilmDescriptor_FilmAspectRatio"; - case PID_FilmDescriptor_Manufacturer: return L"PID_FilmDescriptor_Manufacturer"; - case PID_FilmDescriptor_Model: return L"PID_FilmDescriptor_Model"; - case PID_FilmDescriptor_FilmGaugeFormat: return L"PID_FilmDescriptor_FilmGaugeFormat"; - case PID_FilmDescriptor_FilmBatchNumber: return L"PID_FilmDescriptor_FilmBatchNumber"; - case PID_TapeDescriptor_FormFactor: return L"PID_TapeDescriptor_FormFactor"; - case PID_TapeDescriptor_VideoSignal: return L"PID_TapeDescriptor_VideoSignal"; - case PID_TapeDescriptor_TapeFormat: return L"PID_TapeDescriptor_TapeFormat"; - case PID_TapeDescriptor_Length: return L"PID_TapeDescriptor_Length"; - case PID_TapeDescriptor_ManufacturerID: return L"PID_TapeDescriptor_ManufacturerID"; - case PID_TapeDescriptor_Model: return L"PID_TapeDescriptor_Model"; - case PID_TapeDescriptor_TapeBatchNumber: return L"PID_TapeDescriptor_TapeBatchNumber"; - case PID_TapeDescriptor_TapeStock: return L"PID_TapeDescriptor_TapeStock"; - case PID_Header_ByteOrder: return L"PID_Header_ByteOrder"; - case PID_Header_LastModified: return L"PID_Header_LastModified"; - case PID_Header_Content: return L"PID_Header_Content"; - case PID_Header_Dictionary: return L"PID_Header_Dictionary"; - case PID_Header_Version: return L"PID_Header_Version"; - case PID_Header_IdentificationList: return L"PID_Header_IdentificationList"; - case PID_Header_ObjectModelVersion: return L"PID_Header_ObjectModelVersion"; - case PID_Header_OperationalPattern: return L"PID_Header_OperationalPattern"; - case PID_Header_EssenceContainers: return L"PID_Header_EssenceContainers"; - case PID_Header_DescriptiveSchemes: return L"PID_Header_DescriptiveSchemes"; - case PID_Identification_CompanyName: return L"PID_Identification_CompanyName"; - case PID_Identification_ProductName: return L"PID_Identification_ProductName"; - case PID_Identification_ProductVersion: return L"PID_Identification_ProductVersion"; - case PID_Identification_ProductVersionString: return L"PID_Identification_ProductVersionString"; - case PID_Identification_ProductID: return L"PID_Identification_ProductID"; - case PID_Identification_Date: return L"PID_Identification_Date"; - case PID_Identification_ToolkitVersion: return L"PID_Identification_ToolkitVersion"; - case PID_Identification_Platform: return L"PID_Identification_Platform"; - case PID_Identification_GenerationAUID: return L"PID_Identification_GenerationAUID"; - case PID_NetworkLocator_URLString: return L"PID_NetworkLocator_URLString"; - case PID_TextLocator_Name: return L"PID_TextLocator_Name"; - case PID_Mob_MobID: return L"PID_Mob_MobID"; - case PID_Mob_Name: return L"PID_Mob_Name"; - case PID_Mob_Slots: return L"PID_Mob_Slots"; - case PID_Mob_LastModified: return L"PID_Mob_LastModified"; - case PID_Mob_CreationTime: return L"PID_Mob_CreationTime"; - case PID_Mob_UserComments: return L"PID_Mob_UserComments"; - case PID_Mob_KLVData: return L"PID_Mob_KLVData"; - case PID_Mob_Attributes: return L"PID_Mob_Attributes"; - case PID_Mob_UsageCode: return L"PID_Mob_UsageCode"; - case PID_CompositionMob_DefaultFadeLength: return L"PID_CompositionMob_DefaultFadeLength"; - case PID_CompositionMob_DefFadeType: return L"PID_CompositionMob_DefFadeType"; - case PID_CompositionMob_DefFadeEditUnit: return L"PID_CompositionMob_DefFadeEditUnit"; - case PID_CompositionMob_Rendering: return L"PID_CompositionMob_Rendering"; - case PID_SourceMob_EssenceDescription: return L"PID_SourceMob_EssenceDescription"; - case PID_MobSlot_SlotID: return L"PID_MobSlot_SlotID"; - case PID_MobSlot_SlotName: return L"PID_MobSlot_SlotName"; - case PID_MobSlot_Segment: return L"PID_MobSlot_Segment"; - case PID_MobSlot_PhysicalTrackNumber: return L"PID_MobSlot_PhysicalTrackNumber"; - case PID_EventMobSlot_EditRate: return L"PID_EventMobSlot_EditRate"; - case PID_EventMobSlot_EventSlotOrigin: return L"PID_EventMobSlot_EventSlotOrigin"; - case PID_TimelineMobSlot_EditRate: return L"PID_TimelineMobSlot_EditRate"; - case PID_TimelineMobSlot_Origin: return L"PID_TimelineMobSlot_Origin"; - case PID_TimelineMobSlot_MarkIn: return L"PID_TimelineMobSlot_MarkIn"; - case PID_TimelineMobSlot_MarkOut: return L"PID_TimelineMobSlot_MarkOut"; - case PID_TimelineMobSlot_UserPos: return L"PID_TimelineMobSlot_UserPos"; - case PID_Parameter_Definition: return L"PID_Parameter_Definition"; - case PID_ConstantValue_Value: return L"PID_ConstantValue_Value"; - case PID_VaryingValue_Interpolation: return L"PID_VaryingValue_Interpolation"; - case PID_VaryingValue_PointList: return L"PID_VaryingValue_PointList"; - case PID_TaggedValue_Name: return L"PID_TaggedValue_Name"; - case PID_TaggedValue_Value: return L"PID_TaggedValue_Value"; - case PID_KLVData_Value: return L"PID_KLVData_Value"; - case PID_DescriptiveMarker_DescribedSlots: return L"PID_DescriptiveMarker_DescribedSlots"; - case PID_DescriptiveMarker_Description: return L"PID_DescriptiveMarker_Description"; - case PID_SoundDescriptor_AudioSamplingRate: return L"PID_SoundDescriptor_AudioSamplingRate"; - case PID_SoundDescriptor_Locked: return L"PID_SoundDescriptor_Locked"; - case PID_SoundDescriptor_AudioRefLevel: return L"PID_SoundDescriptor_AudioRefLevel"; - case PID_SoundDescriptor_ElectroSpatial: return L"PID_SoundDescriptor_ElectroSpatial"; - case PID_SoundDescriptor_Channels: return L"PID_SoundDescriptor_Channels"; - case PID_SoundDescriptor_QuantizationBits: return L"PID_SoundDescriptor_QuantizationBits"; - case PID_SoundDescriptor_DialNorm: return L"PID_SoundDescriptor_DialNorm"; - case PID_SoundDescriptor_Compression: return L"PID_SoundDescriptor_Compression"; - case PID_DataEssenceDescriptor_DataEssenceCoding: return L"PID_DataEssenceDescriptor_DataEssenceCoding"; - case PID_MultipleDescriptor_FileDescriptors: return L"PID_MultipleDescriptor_FileDescriptors"; - case PID_DescriptiveClip_DescribedSlotIDs: return L"PID_DescriptiveClip_DescribedSlotIDs"; - case PID_AES3PCMDescriptor_Emphasis: return L"PID_AES3PCMDescriptor_Emphasis"; - case PID_AES3PCMDescriptor_BlockStartOffset: return L"PID_AES3PCMDescriptor_BlockStartOffset"; - case PID_AES3PCMDescriptor_AuxBitsMode: return L"PID_AES3PCMDescriptor_AuxBitsMode"; - case PID_AES3PCMDescriptor_ChannelStatusMode: return L"PID_AES3PCMDescriptor_ChannelStatusMode"; - case PID_AES3PCMDescriptor_FixedChannelStatusData: return L"PID_AES3PCMDescriptor_FixedChannelStatusData"; - case PID_AES3PCMDescriptor_UserDataMode: return L"PID_AES3PCMDescriptor_UserDataMode"; - case PID_AES3PCMDescriptor_FixedUserData: return L"PID_AES3PCMDescriptor_FixedUserData"; - case PID_PCMDescriptor_BlockAlign: return L"PID_PCMDescriptor_BlockAlign"; - case PID_PCMDescriptor_SequenceOffset: return L"PID_PCMDescriptor_SequenceOffset"; - case PID_PCMDescriptor_AverageBPS: return L"PID_PCMDescriptor_AverageBPS"; - case PID_PCMDescriptor_ChannelAssignment: return L"PID_PCMDescriptor_ChannelAssignment"; - case PID_PCMDescriptor_PeakEnvelopeVersion: return L"PID_PCMDescriptor_PeakEnvelopeVersion"; - case PID_PCMDescriptor_PeakEnvelopeFormat: return L"PID_PCMDescriptor_PeakEnvelopeFormat"; - case PID_PCMDescriptor_PointsPerPeakValue: return L"PID_PCMDescriptor_PointsPerPeakValue"; - case PID_PCMDescriptor_PeakEnvelopeBlockSize: return L"PID_PCMDescriptor_PeakEnvelopeBlockSize"; - case PID_PCMDescriptor_PeakChannels: return L"PID_PCMDescriptor_PeakChannels"; - case PID_PCMDescriptor_PeakFrames: return L"PID_PCMDescriptor_PeakFrames"; - case PID_PCMDescriptor_PeakOfPeaksPosition: return L"PID_PCMDescriptor_PeakOfPeaksPosition"; - case PID_PCMDescriptor_PeakEnvelopeTimestamp: return L"PID_PCMDescriptor_PeakEnvelopeTimestamp"; - case PID_PCMDescriptor_PeakEnvelopeData: return L"PID_PCMDescriptor_PeakEnvelopeData"; - case PID_KLVDataDefinition_KLVDataType: return L"PID_KLVDataDefinition_KLVDataType"; - case PID_AuxiliaryDescriptor_MimeType: return L"PID_AuxiliaryDescriptor_MimeType"; - case PID_AuxiliaryDescriptor_CharSet: return L"PID_AuxiliaryDescriptor_CharSet"; - case PID_RIFFChunk_ChunkID: return L"PID_RIFFChunk_ChunkID"; - case PID_RIFFChunk_ChunkLength: return L"PID_RIFFChunk_ChunkLength"; - case PID_RIFFChunk_ChunkData: return L"PID_RIFFChunk_ChunkData"; - case PID_BWFImportDescriptor_QltyFileSecurityReport: return L"PID_BWFImportDescriptor_QltyFileSecurityReport"; - case PID_BWFImportDescriptor_QltyFileSecurityWave: return L"PID_BWFImportDescriptor_QltyFileSecurityWave"; - case PID_BWFImportDescriptor_BextCodingHistory: return L"PID_BWFImportDescriptor_BextCodingHistory"; - case PID_BWFImportDescriptor_QltyBasicData: return L"PID_BWFImportDescriptor_QltyBasicData"; - case PID_BWFImportDescriptor_QltyStartOfModulation: return L"PID_BWFImportDescriptor_QltyStartOfModulation"; - case PID_BWFImportDescriptor_QltyQualityEvent: return L"PID_BWFImportDescriptor_QltyQualityEvent"; - case PID_BWFImportDescriptor_QltyEndOfModulation: return L"PID_BWFImportDescriptor_QltyEndOfModulation"; - case PID_BWFImportDescriptor_QltyQualityParameter: return L"PID_BWFImportDescriptor_QltyQualityParameter"; - case PID_BWFImportDescriptor_QltyOperatorComment: return L"PID_BWFImportDescriptor_QltyOperatorComment"; - case PID_BWFImportDescriptor_QltyCueSheet: return L"PID_BWFImportDescriptor_QltyCueSheet"; - case PID_BWFImportDescriptor_UnknownBWFChunks: return L"PID_BWFImportDescriptor_UnknownBWFChunks"; + case PID_Root_MetaDictionary: return "PID_Root_MetaDictionary"; + case PID_Root_Header: return "PID_Root_Header"; + case PID_InterchangeObject_ObjClass: return "PID_InterchangeObject_ObjClass"; + case PID_InterchangeObject_Generation: return "PID_InterchangeObject_Generation"; + case PID_Component_DataDefinition: return "PID_Component_DataDefinition"; + case PID_Component_Length: return "PID_Component_Length"; + case PID_Component_KLVData: return "PID_Component_KLVData"; + case PID_Component_UserComments: return "PID_Component_UserComments"; + case PID_Component_Attributes: return "PID_Component_Attributes"; + case PID_EdgeCode_Start: return "PID_EdgeCode_Start"; + case PID_EdgeCode_FilmKind: return "PID_EdgeCode_FilmKind"; + case PID_EdgeCode_CodeFormat: return "PID_EdgeCode_CodeFormat"; + case PID_EdgeCode_Header: return "PID_EdgeCode_Header"; + case PID_EssenceGroup_Choices: return "PID_EssenceGroup_Choices"; + case PID_EssenceGroup_StillFrame: return "PID_EssenceGroup_StillFrame"; + case PID_Event_Position: return "PID_Event_Position"; + case PID_Event_Comment: return "PID_Event_Comment"; + case PID_GPITrigger_ActiveState: return "PID_GPITrigger_ActiveState"; + case PID_CommentMarker_Annotation: return "PID_CommentMarker_Annotation"; + case PID_OperationGroup_Operation: return "PID_OperationGroup_Operation"; + case PID_OperationGroup_InputSegments: return "PID_OperationGroup_InputSegments"; + case PID_OperationGroup_Parameters: return "PID_OperationGroup_Parameters"; + case PID_OperationGroup_BypassOverride: return "PID_OperationGroup_BypassOverride"; + case PID_OperationGroup_Rendering: return "PID_OperationGroup_Rendering"; + case PID_NestedScope_Slots: return "PID_NestedScope_Slots"; + case PID_Pulldown_InputSegment: return "PID_Pulldown_InputSegment"; + case PID_Pulldown_PulldownKind: return "PID_Pulldown_PulldownKind"; + case PID_Pulldown_PulldownDirection: return "PID_Pulldown_PulldownDirection"; + case PID_Pulldown_PhaseFrame: return "PID_Pulldown_PhaseFrame"; + case PID_ScopeReference_RelativeScope: return "PID_ScopeReference_RelativeScope"; + case PID_ScopeReference_RelativeSlot: return "PID_ScopeReference_RelativeSlot"; + case PID_Selector_Selected: return "PID_Selector_Selected"; + case PID_Selector_Alternates: return "PID_Selector_Alternates"; + case PID_Sequence_Components: return "PID_Sequence_Components"; + case PID_SourceReference_SourceID: return "PID_SourceReference_SourceID"; + case PID_SourceReference_SourceMobSlotID: return "PID_SourceReference_SourceMobSlotID"; + case PID_SourceReference_ChannelIDs: return "PID_SourceReference_ChannelIDs"; + case PID_SourceReference_MonoSourceSlotIDs: return "PID_SourceReference_MonoSourceSlotIDs"; + case PID_SourceClip_StartTime: return "PID_SourceClip_StartTime"; + case PID_SourceClip_FadeInLength: return "PID_SourceClip_FadeInLength"; + case PID_SourceClip_FadeInType: return "PID_SourceClip_FadeInType"; + case PID_SourceClip_FadeOutLength: return "PID_SourceClip_FadeOutLength"; + case PID_SourceClip_FadeOutType: return "PID_SourceClip_FadeOutType"; + case PID_HTMLClip_BeginAnchor: return "PID_HTMLClip_BeginAnchor"; + case PID_HTMLClip_EndAnchor: return "PID_HTMLClip_EndAnchor"; + case PID_Timecode_Start: return "PID_Timecode_Start"; + case PID_Timecode_FPS: return "PID_Timecode_FPS"; + case PID_Timecode_Drop: return "PID_Timecode_Drop"; + case PID_TimecodeStream_SampleRate: return "PID_TimecodeStream_SampleRate"; + case PID_TimecodeStream_Source: return "PID_TimecodeStream_Source"; + case PID_TimecodeStream_SourceType: return "PID_TimecodeStream_SourceType"; + case PID_TimecodeStream12M_IncludeSync: return "PID_TimecodeStream12M_IncludeSync"; + case PID_Transition_OperationGroup: return "PID_Transition_OperationGroup"; + case PID_Transition_CutPoint: return "PID_Transition_CutPoint"; + case PID_ContentStorage_Mobs: return "PID_ContentStorage_Mobs"; + case PID_ContentStorage_EssenceData: return "PID_ContentStorage_EssenceData"; + case PID_ControlPoint_Value: return "PID_ControlPoint_Value"; + case PID_ControlPoint_Time: return "PID_ControlPoint_Time"; + case PID_ControlPoint_EditHint: return "PID_ControlPoint_EditHint"; + case PID_DefinitionObject_Identification: return "PID_DefinitionObject_Identification"; + case PID_DefinitionObject_Name: return "PID_DefinitionObject_Name"; + case PID_DefinitionObject_Description: return "PID_DefinitionObject_Description"; + case PID_OperationDefinition_DataDefinition: return "PID_OperationDefinition_DataDefinition"; + case PID_OperationDefinition_IsTimeWarp: return "PID_OperationDefinition_IsTimeWarp"; + case PID_OperationDefinition_DegradeTo: return "PID_OperationDefinition_DegradeTo"; + case PID_OperationDefinition_OperationCategory: return "PID_OperationDefinition_OperationCategory"; + case PID_OperationDefinition_NumberInputs: return "PID_OperationDefinition_NumberInputs"; + case PID_OperationDefinition_Bypass: return "PID_OperationDefinition_Bypass"; + case PID_OperationDefinition_ParametersDefined: return "PID_OperationDefinition_ParametersDefined"; + case PID_ParameterDefinition_Type: return "PID_ParameterDefinition_Type"; + case PID_ParameterDefinition_DisplayUnits: return "PID_ParameterDefinition_DisplayUnits"; + case PID_PluginDefinition_PluginCategory: return "PID_PluginDefinition_PluginCategory"; + case PID_PluginDefinition_VersionNumber: return "PID_PluginDefinition_VersionNumber"; + case PID_PluginDefinition_VersionString: return "PID_PluginDefinition_VersionString"; + case PID_PluginDefinition_Manufacturer: return "PID_PluginDefinition_Manufacturer"; + case PID_PluginDefinition_ManufacturerInfo: return "PID_PluginDefinition_ManufacturerInfo"; + case PID_PluginDefinition_ManufacturerID: return "PID_PluginDefinition_ManufacturerID"; + case PID_PluginDefinition_Platform: return "PID_PluginDefinition_Platform"; + case PID_PluginDefinition_MinPlatformVersion: return "PID_PluginDefinition_MinPlatformVersion"; + case PID_PluginDefinition_MaxPlatformVersion: return "PID_PluginDefinition_MaxPlatformVersion"; + case PID_PluginDefinition_Engine: return "PID_PluginDefinition_Engine"; + case PID_PluginDefinition_MinEngineVersion: return "PID_PluginDefinition_MinEngineVersion"; + case PID_PluginDefinition_MaxEngineVersion: return "PID_PluginDefinition_MaxEngineVersion"; + case PID_PluginDefinition_PluginAPI: return "PID_PluginDefinition_PluginAPI"; + case PID_PluginDefinition_MinPluginAPI: return "PID_PluginDefinition_MinPluginAPI"; + case PID_PluginDefinition_MaxPluginAPI: return "PID_PluginDefinition_MaxPluginAPI"; + case PID_PluginDefinition_SoftwareOnly: return "PID_PluginDefinition_SoftwareOnly"; + case PID_PluginDefinition_Accelerator: return "PID_PluginDefinition_Accelerator"; + case PID_PluginDefinition_Locators: return "PID_PluginDefinition_Locators"; + case PID_PluginDefinition_Authentication: return "PID_PluginDefinition_Authentication"; + case PID_PluginDefinition_DefinitionObject: return "PID_PluginDefinition_DefinitionObject"; + case PID_CodecDefinition_FileDescriptorClass: return "PID_CodecDefinition_FileDescriptorClass"; + case PID_CodecDefinition_DataDefinitions: return "PID_CodecDefinition_DataDefinitions"; + case PID_ContainerDefinition_EssenceIsIdentified: return "PID_ContainerDefinition_EssenceIsIdentified"; + case PID_Dictionary_OperationDefinitions: return "PID_Dictionary_OperationDefinitions"; + case PID_Dictionary_ParameterDefinitions: return "PID_Dictionary_ParameterDefinitions"; + case PID_Dictionary_DataDefinitions: return "PID_Dictionary_DataDefinitions"; + case PID_Dictionary_PluginDefinitions: return "PID_Dictionary_PluginDefinitions"; + case PID_Dictionary_CodecDefinitions: return "PID_Dictionary_CodecDefinitions"; + case PID_Dictionary_ContainerDefinitions: return "PID_Dictionary_ContainerDefinitions"; + case PID_Dictionary_InterpolationDefinitions: return "PID_Dictionary_InterpolationDefinitions"; + case PID_Dictionary_KLVDataDefinitions: return "PID_Dictionary_KLVDataDefinitions"; + case PID_Dictionary_TaggedValueDefinitions: return "PID_Dictionary_TaggedValueDefinitions"; + case PID_EssenceData_MobID: return "PID_EssenceData_MobID"; + case PID_EssenceData_Data: return "PID_EssenceData_Data"; + case PID_EssenceData_SampleIndex: return "PID_EssenceData_SampleIndex"; + case PID_EssenceDescriptor_Locator: return "PID_EssenceDescriptor_Locator"; + case PID_FileDescriptor_SampleRate: return "PID_FileDescriptor_SampleRate"; + case PID_FileDescriptor_Length: return "PID_FileDescriptor_Length"; + case PID_FileDescriptor_ContainerFormat: return "PID_FileDescriptor_ContainerFormat"; + case PID_FileDescriptor_CodecDefinition: return "PID_FileDescriptor_CodecDefinition"; + case PID_FileDescriptor_LinkedSlotID: return "PID_FileDescriptor_LinkedSlotID"; + case PID_AIFCDescriptor_Summary: return "PID_AIFCDescriptor_Summary"; + case PID_DigitalImageDescriptor_Compression: return "PID_DigitalImageDescriptor_Compression"; + case PID_DigitalImageDescriptor_StoredHeight: return "PID_DigitalImageDescriptor_StoredHeight"; + case PID_DigitalImageDescriptor_StoredWidth: return "PID_DigitalImageDescriptor_StoredWidth"; + case PID_DigitalImageDescriptor_SampledHeight: return "PID_DigitalImageDescriptor_SampledHeight"; + case PID_DigitalImageDescriptor_SampledWidth: return "PID_DigitalImageDescriptor_SampledWidth"; + case PID_DigitalImageDescriptor_SampledXOffset: return "PID_DigitalImageDescriptor_SampledXOffset"; + case PID_DigitalImageDescriptor_SampledYOffset: return "PID_DigitalImageDescriptor_SampledYOffset"; + case PID_DigitalImageDescriptor_DisplayHeight: return "PID_DigitalImageDescriptor_DisplayHeight"; + case PID_DigitalImageDescriptor_DisplayWidth: return "PID_DigitalImageDescriptor_DisplayWidth"; + case PID_DigitalImageDescriptor_DisplayXOffset: return "PID_DigitalImageDescriptor_DisplayXOffset"; + case PID_DigitalImageDescriptor_DisplayYOffset: return "PID_DigitalImageDescriptor_DisplayYOffset"; + case PID_DigitalImageDescriptor_FrameLayout: return "PID_DigitalImageDescriptor_FrameLayout"; + case PID_DigitalImageDescriptor_VideoLineMap: return "PID_DigitalImageDescriptor_VideoLineMap"; + case PID_DigitalImageDescriptor_ImageAspectRatio: return "PID_DigitalImageDescriptor_ImageAspectRatio"; + case PID_DigitalImageDescriptor_AlphaTransparency: return "PID_DigitalImageDescriptor_AlphaTransparency"; + case PID_DigitalImageDescriptor_TransferCharacteristic: return "PID_DigitalImageDescriptor_TransferCharacteristic"; + case PID_DigitalImageDescriptor_ColorPrimaries: return "PID_DigitalImageDescriptor_ColorPrimaries"; + case PID_DigitalImageDescriptor_CodingEquations: return "PID_DigitalImageDescriptor_CodingEquations"; + case PID_DigitalImageDescriptor_ImageAlignmentFactor: return "PID_DigitalImageDescriptor_ImageAlignmentFactor"; + case PID_DigitalImageDescriptor_FieldDominance: return "PID_DigitalImageDescriptor_FieldDominance"; + case PID_DigitalImageDescriptor_FieldStartOffset: return "PID_DigitalImageDescriptor_FieldStartOffset"; + case PID_DigitalImageDescriptor_FieldEndOffset: return "PID_DigitalImageDescriptor_FieldEndOffset"; + case PID_DigitalImageDescriptor_SignalStandard: return "PID_DigitalImageDescriptor_SignalStandard"; + case PID_DigitalImageDescriptor_StoredF2Offset: return "PID_DigitalImageDescriptor_StoredF2Offset"; + case PID_DigitalImageDescriptor_DisplayF2Offset: return "PID_DigitalImageDescriptor_DisplayF2Offset"; + case PID_DigitalImageDescriptor_ActiveFormatDescriptor: return "PID_DigitalImageDescriptor_ActiveFormatDescriptor"; + case PID_CDCIDescriptor_ComponentWidth: return "PID_CDCIDescriptor_ComponentWidth"; + case PID_CDCIDescriptor_HorizontalSubsampling: return "PID_CDCIDescriptor_HorizontalSubsampling"; + case PID_CDCIDescriptor_ColorSiting: return "PID_CDCIDescriptor_ColorSiting"; + case PID_CDCIDescriptor_BlackReferenceLevel: return "PID_CDCIDescriptor_BlackReferenceLevel"; + case PID_CDCIDescriptor_WhiteReferenceLevel: return "PID_CDCIDescriptor_WhiteReferenceLevel"; + case PID_CDCIDescriptor_ColorRange: return "PID_CDCIDescriptor_ColorRange"; + case PID_CDCIDescriptor_PaddingBits: return "PID_CDCIDescriptor_PaddingBits"; + case PID_CDCIDescriptor_VerticalSubsampling: return "PID_CDCIDescriptor_VerticalSubsampling"; + case PID_CDCIDescriptor_AlphaSamplingWidth: return "PID_CDCIDescriptor_AlphaSamplingWidth"; + case PID_CDCIDescriptor_ReversedByteOrder: return "PID_CDCIDescriptor_ReversedByteOrder"; + case PID_RGBADescriptor_PixelLayout: return "PID_RGBADescriptor_PixelLayout"; + case PID_RGBADescriptor_Palette: return "PID_RGBADescriptor_Palette"; + case PID_RGBADescriptor_PaletteLayout: return "PID_RGBADescriptor_PaletteLayout"; + case PID_RGBADescriptor_ScanningDirection: return "PID_RGBADescriptor_ScanningDirection"; + case PID_RGBADescriptor_ComponentMaxRef: return "PID_RGBADescriptor_ComponentMaxRef"; + case PID_RGBADescriptor_ComponentMinRef: return "PID_RGBADescriptor_ComponentMinRef"; + case PID_RGBADescriptor_AlphaMaxRef: return "PID_RGBADescriptor_AlphaMaxRef"; + case PID_RGBADescriptor_AlphaMinRef: return "PID_RGBADescriptor_AlphaMinRef"; + case PID_TIFFDescriptor_IsUniform: return "PID_TIFFDescriptor_IsUniform"; + case PID_TIFFDescriptor_IsContiguous: return "PID_TIFFDescriptor_IsContiguous"; + case PID_TIFFDescriptor_LeadingLines: return "PID_TIFFDescriptor_LeadingLines"; + case PID_TIFFDescriptor_TrailingLines: return "PID_TIFFDescriptor_TrailingLines"; + case PID_TIFFDescriptor_JPEGTableID: return "PID_TIFFDescriptor_JPEGTableID"; + case PID_TIFFDescriptor_Summary: return "PID_TIFFDescriptor_Summary"; + case PID_WAVEDescriptor_Summary: return "PID_WAVEDescriptor_Summary"; + case PID_FilmDescriptor_FilmFormat: return "PID_FilmDescriptor_FilmFormat"; + case PID_FilmDescriptor_FrameRate: return "PID_FilmDescriptor_FrameRate"; + case PID_FilmDescriptor_PerforationsPerFrame: return "PID_FilmDescriptor_PerforationsPerFrame"; + case PID_FilmDescriptor_FilmAspectRatio: return "PID_FilmDescriptor_FilmAspectRatio"; + case PID_FilmDescriptor_Manufacturer: return "PID_FilmDescriptor_Manufacturer"; + case PID_FilmDescriptor_Model: return "PID_FilmDescriptor_Model"; + case PID_FilmDescriptor_FilmGaugeFormat: return "PID_FilmDescriptor_FilmGaugeFormat"; + case PID_FilmDescriptor_FilmBatchNumber: return "PID_FilmDescriptor_FilmBatchNumber"; + case PID_TapeDescriptor_FormFactor: return "PID_TapeDescriptor_FormFactor"; + case PID_TapeDescriptor_VideoSignal: return "PID_TapeDescriptor_VideoSignal"; + case PID_TapeDescriptor_TapeFormat: return "PID_TapeDescriptor_TapeFormat"; + case PID_TapeDescriptor_Length: return "PID_TapeDescriptor_Length"; + case PID_TapeDescriptor_ManufacturerID: return "PID_TapeDescriptor_ManufacturerID"; + case PID_TapeDescriptor_Model: return "PID_TapeDescriptor_Model"; + case PID_TapeDescriptor_TapeBatchNumber: return "PID_TapeDescriptor_TapeBatchNumber"; + case PID_TapeDescriptor_TapeStock: return "PID_TapeDescriptor_TapeStock"; + case PID_Header_ByteOrder: return "PID_Header_ByteOrder"; + case PID_Header_LastModified: return "PID_Header_LastModified"; + case PID_Header_Content: return "PID_Header_Content"; + case PID_Header_Dictionary: return "PID_Header_Dictionary"; + case PID_Header_Version: return "PID_Header_Version"; + case PID_Header_IdentificationList: return "PID_Header_IdentificationList"; + case PID_Header_ObjectModelVersion: return "PID_Header_ObjectModelVersion"; + case PID_Header_OperationalPattern: return "PID_Header_OperationalPattern"; + case PID_Header_EssenceContainers: return "PID_Header_EssenceContainers"; + case PID_Header_DescriptiveSchemes: return "PID_Header_DescriptiveSchemes"; + case PID_Identification_CompanyName: return "PID_Identification_CompanyName"; + case PID_Identification_ProductName: return "PID_Identification_ProductName"; + case PID_Identification_ProductVersion: return "PID_Identification_ProductVersion"; + case PID_Identification_ProductVersionString: return "PID_Identification_ProductVersionString"; + case PID_Identification_ProductID: return "PID_Identification_ProductID"; + case PID_Identification_Date: return "PID_Identification_Date"; + case PID_Identification_ToolkitVersion: return "PID_Identification_ToolkitVersion"; + case PID_Identification_Platform: return "PID_Identification_Platform"; + case PID_Identification_GenerationAUID: return "PID_Identification_GenerationAUID"; + case PID_NetworkLocator_URLString: return "PID_NetworkLocator_URLString"; + case PID_TextLocator_Name: return "PID_TextLocator_Name"; + case PID_Mob_MobID: return "PID_Mob_MobID"; + case PID_Mob_Name: return "PID_Mob_Name"; + case PID_Mob_Slots: return "PID_Mob_Slots"; + case PID_Mob_LastModified: return "PID_Mob_LastModified"; + case PID_Mob_CreationTime: return "PID_Mob_CreationTime"; + case PID_Mob_UserComments: return "PID_Mob_UserComments"; + case PID_Mob_KLVData: return "PID_Mob_KLVData"; + case PID_Mob_Attributes: return "PID_Mob_Attributes"; + case PID_Mob_UsageCode: return "PID_Mob_UsageCode"; + case PID_CompositionMob_DefaultFadeLength: return "PID_CompositionMob_DefaultFadeLength"; + case PID_CompositionMob_DefFadeType: return "PID_CompositionMob_DefFadeType"; + case PID_CompositionMob_DefFadeEditUnit: return "PID_CompositionMob_DefFadeEditUnit"; + case PID_CompositionMob_Rendering: return "PID_CompositionMob_Rendering"; + case PID_SourceMob_EssenceDescription: return "PID_SourceMob_EssenceDescription"; + case PID_MobSlot_SlotID: return "PID_MobSlot_SlotID"; + case PID_MobSlot_SlotName: return "PID_MobSlot_SlotName"; + case PID_MobSlot_Segment: return "PID_MobSlot_Segment"; + case PID_MobSlot_PhysicalTrackNumber: return "PID_MobSlot_PhysicalTrackNumber"; + case PID_EventMobSlot_EditRate: return "PID_EventMobSlot_EditRate"; + case PID_EventMobSlot_EventSlotOrigin: return "PID_EventMobSlot_EventSlotOrigin"; + case PID_TimelineMobSlot_EditRate: return "PID_TimelineMobSlot_EditRate"; + case PID_TimelineMobSlot_Origin: return "PID_TimelineMobSlot_Origin"; + case PID_TimelineMobSlot_MarkIn: return "PID_TimelineMobSlot_MarkIn"; + case PID_TimelineMobSlot_MarkOut: return "PID_TimelineMobSlot_MarkOut"; + case PID_TimelineMobSlot_UserPos: return "PID_TimelineMobSlot_UserPos"; + case PID_Parameter_Definition: return "PID_Parameter_Definition"; + case PID_ConstantValue_Value: return "PID_ConstantValue_Value"; + case PID_VaryingValue_Interpolation: return "PID_VaryingValue_Interpolation"; + case PID_VaryingValue_PointList: return "PID_VaryingValue_PointList"; + case PID_TaggedValue_Name: return "PID_TaggedValue_Name"; + case PID_TaggedValue_Value: return "PID_TaggedValue_Value"; + case PID_KLVData_Value: return "PID_KLVData_Value"; + case PID_DescriptiveMarker_DescribedSlots: return "PID_DescriptiveMarker_DescribedSlots"; + case PID_DescriptiveMarker_Description: return "PID_DescriptiveMarker_Description"; + case PID_SoundDescriptor_AudioSamplingRate: return "PID_SoundDescriptor_AudioSamplingRate"; + case PID_SoundDescriptor_Locked: return "PID_SoundDescriptor_Locked"; + case PID_SoundDescriptor_AudioRefLevel: return "PID_SoundDescriptor_AudioRefLevel"; + case PID_SoundDescriptor_ElectroSpatial: return "PID_SoundDescriptor_ElectroSpatial"; + case PID_SoundDescriptor_Channels: return "PID_SoundDescriptor_Channels"; + case PID_SoundDescriptor_QuantizationBits: return "PID_SoundDescriptor_QuantizationBits"; + case PID_SoundDescriptor_DialNorm: return "PID_SoundDescriptor_DialNorm"; + case PID_SoundDescriptor_Compression: return "PID_SoundDescriptor_Compression"; + case PID_DataEssenceDescriptor_DataEssenceCoding: return "PID_DataEssenceDescriptor_DataEssenceCoding"; + case PID_MultipleDescriptor_FileDescriptors: return "PID_MultipleDescriptor_FileDescriptors"; + case PID_DescriptiveClip_DescribedSlotIDs: return "PID_DescriptiveClip_DescribedSlotIDs"; + case PID_AES3PCMDescriptor_Emphasis: return "PID_AES3PCMDescriptor_Emphasis"; + case PID_AES3PCMDescriptor_BlockStartOffset: return "PID_AES3PCMDescriptor_BlockStartOffset"; + case PID_AES3PCMDescriptor_AuxBitsMode: return "PID_AES3PCMDescriptor_AuxBitsMode"; + case PID_AES3PCMDescriptor_ChannelStatusMode: return "PID_AES3PCMDescriptor_ChannelStatusMode"; + case PID_AES3PCMDescriptor_FixedChannelStatusData: return "PID_AES3PCMDescriptor_FixedChannelStatusData"; + case PID_AES3PCMDescriptor_UserDataMode: return "PID_AES3PCMDescriptor_UserDataMode"; + case PID_AES3PCMDescriptor_FixedUserData: return "PID_AES3PCMDescriptor_FixedUserData"; + case PID_PCMDescriptor_BlockAlign: return "PID_PCMDescriptor_BlockAlign"; + case PID_PCMDescriptor_SequenceOffset: return "PID_PCMDescriptor_SequenceOffset"; + case PID_PCMDescriptor_AverageBPS: return "PID_PCMDescriptor_AverageBPS"; + case PID_PCMDescriptor_ChannelAssignment: return "PID_PCMDescriptor_ChannelAssignment"; + case PID_PCMDescriptor_PeakEnvelopeVersion: return "PID_PCMDescriptor_PeakEnvelopeVersion"; + case PID_PCMDescriptor_PeakEnvelopeFormat: return "PID_PCMDescriptor_PeakEnvelopeFormat"; + case PID_PCMDescriptor_PointsPerPeakValue: return "PID_PCMDescriptor_PointsPerPeakValue"; + case PID_PCMDescriptor_PeakEnvelopeBlockSize: return "PID_PCMDescriptor_PeakEnvelopeBlockSize"; + case PID_PCMDescriptor_PeakChannels: return "PID_PCMDescriptor_PeakChannels"; + case PID_PCMDescriptor_PeakFrames: return "PID_PCMDescriptor_PeakFrames"; + case PID_PCMDescriptor_PeakOfPeaksPosition: return "PID_PCMDescriptor_PeakOfPeaksPosition"; + case PID_PCMDescriptor_PeakEnvelopeTimestamp: return "PID_PCMDescriptor_PeakEnvelopeTimestamp"; + case PID_PCMDescriptor_PeakEnvelopeData: return "PID_PCMDescriptor_PeakEnvelopeData"; + case PID_KLVDataDefinition_KLVDataType: return "PID_KLVDataDefinition_KLVDataType"; + case PID_AuxiliaryDescriptor_MimeType: return "PID_AuxiliaryDescriptor_MimeType"; + case PID_AuxiliaryDescriptor_CharSet: return "PID_AuxiliaryDescriptor_CharSet"; + case PID_RIFFChunk_ChunkID: return "PID_RIFFChunk_ChunkID"; + case PID_RIFFChunk_ChunkLength: return "PID_RIFFChunk_ChunkLength"; + case PID_RIFFChunk_ChunkData: return "PID_RIFFChunk_ChunkData"; + case PID_BWFImportDescriptor_QltyFileSecurityReport: return "PID_BWFImportDescriptor_QltyFileSecurityReport"; + case PID_BWFImportDescriptor_QltyFileSecurityWave: return "PID_BWFImportDescriptor_QltyFileSecurityWave"; + case PID_BWFImportDescriptor_BextCodingHistory: return "PID_BWFImportDescriptor_BextCodingHistory"; + case PID_BWFImportDescriptor_QltyBasicData: return "PID_BWFImportDescriptor_QltyBasicData"; + case PID_BWFImportDescriptor_QltyStartOfModulation: return "PID_BWFImportDescriptor_QltyStartOfModulation"; + case PID_BWFImportDescriptor_QltyQualityEvent: return "PID_BWFImportDescriptor_QltyQualityEvent"; + case PID_BWFImportDescriptor_QltyEndOfModulation: return "PID_BWFImportDescriptor_QltyEndOfModulation"; + case PID_BWFImportDescriptor_QltyQualityParameter: return "PID_BWFImportDescriptor_QltyQualityParameter"; + case PID_BWFImportDescriptor_QltyOperatorComment: return "PID_BWFImportDescriptor_QltyOperatorComment"; + case PID_BWFImportDescriptor_QltyCueSheet: return "PID_BWFImportDescriptor_QltyCueSheet"; + case PID_BWFImportDescriptor_UnknownBWFChunks: return "PID_BWFImportDescriptor_UnknownBWFChunks"; /* the following is marked as "dynamic" in ref implementation : * AAF/ref-impl/include/ref-api/AAFTypes.h @@ -1223,40 +1346,40 @@ const wchar_t * aaft_PIDToText( AAF_Data *aafd, aafPID_t pid ) * case PID_MPEGVideoDescriptor_ProfileAndLevel: */ - case PID_ClassDefinition_ParentClass: return L"PID_ClassDefinition_ParentClass"; - case PID_ClassDefinition_Properties: return L"PID_ClassDefinition_Properties"; - case PID_ClassDefinition_IsConcrete: return L"PID_ClassDefinition_IsConcrete"; - case PID_PropertyDefinition_Type: return L"PID_PropertyDefinition_Type"; - case PID_PropertyDefinition_IsOptional: return L"PID_PropertyDefinition_IsOptional"; - case PID_PropertyDefinition_LocalIdentification: return L"PID_PropertyDefinition_LocalIdentification"; - case PID_PropertyDefinition_IsUniqueIdentifier: return L"PID_PropertyDefinition_IsUniqueIdentifier"; - case PID_TypeDefinitionInteger_Size: return L"PID_TypeDefinitionInteger_Size"; - case PID_TypeDefinitionInteger_IsSigned: return L"PID_TypeDefinitionInteger_IsSigned"; - case PID_TypeDefinitionStrongObjectReference_ReferencedType: return L"PID_TypeDefinitionStrongObjectReference_ReferencedType"; - case PID_TypeDefinitionWeakObjectReference_ReferencedType: return L"PID_TypeDefinitionWeakObjectReference_ReferencedType"; - case PID_TypeDefinitionWeakObjectReference_TargetSet: return L"PID_TypeDefinitionWeakObjectReference_TargetSet"; - case PID_TypeDefinitionEnumeration_ElementType: return L"PID_TypeDefinitionEnumeration_ElementType"; - case PID_TypeDefinitionEnumeration_ElementNames: return L"PID_TypeDefinitionEnumeration_ElementNames"; - case PID_TypeDefinitionEnumeration_ElementValues: return L"PID_TypeDefinitionEnumeration_ElementValues"; - case PID_TypeDefinitionFixedArray_ElementType: return L"PID_TypeDefinitionFixedArray_ElementType"; - case PID_TypeDefinitionFixedArray_ElementCount: return L"PID_TypeDefinitionFixedArray_ElementCount"; - case PID_TypeDefinitionVariableArray_ElementType: return L"PID_TypeDefinitionVariableArray_ElementType"; - case PID_TypeDefinitionSet_ElementType: return L"PID_TypeDefinitionSet_ElementType"; - case PID_TypeDefinitionString_ElementType: return L"PID_TypeDefinitionString_ElementType"; - case PID_TypeDefinitionRecord_MemberTypes: return L"PID_TypeDefinitionRecord_MemberTypes"; - case PID_TypeDefinitionRecord_MemberNames: return L"PID_TypeDefinitionRecord_MemberNames"; - case PID_TypeDefinitionRename_RenamedType: return L"PID_TypeDefinitionRename_RenamedType"; - case PID_TypeDefinitionExtendibleEnumeration_ElementNames: return L"PID_TypeDefinitionExtendibleEnumeration_ElementNames"; - case PID_TypeDefinitionExtendibleEnumeration_ElementValues: return L"PID_TypeDefinitionExtendibleEnumeration_ElementValues"; - case PID_MetaDefinition_Identification: return L"PID_MetaDefinition_Identification"; - case PID_MetaDefinition_Name: return L"PID_MetaDefinition_Name"; - case PID_MetaDefinition_Description: return L"PID_MetaDefinition_Description"; - case PID_MetaDictionary_ClassDefinitions: return L"PID_MetaDictionary_ClassDefinitions"; - case PID_MetaDictionary_TypeDefinitions: return L"PID_MetaDictionary_TypeDefinitions"; + case PID_ClassDefinition_ParentClass: return "PID_ClassDefinition_ParentClass"; + case PID_ClassDefinition_Properties: return "PID_ClassDefinition_Properties"; + case PID_ClassDefinition_IsConcrete: return "PID_ClassDefinition_IsConcrete"; + case PID_PropertyDefinition_Type: return "PID_PropertyDefinition_Type"; + case PID_PropertyDefinition_IsOptional: return "PID_PropertyDefinition_IsOptional"; + case PID_PropertyDefinition_LocalIdentification: return "PID_PropertyDefinition_LocalIdentification"; + case PID_PropertyDefinition_IsUniqueIdentifier: return "PID_PropertyDefinition_IsUniqueIdentifier"; + case PID_TypeDefinitionInteger_Size: return "PID_TypeDefinitionInteger_Size"; + case PID_TypeDefinitionInteger_IsSigned: return "PID_TypeDefinitionInteger_IsSigned"; + case PID_TypeDefinitionStrongObjectReference_ReferencedType: return "PID_TypeDefinitionStrongObjectReference_ReferencedType"; + case PID_TypeDefinitionWeakObjectReference_ReferencedType: return "PID_TypeDefinitionWeakObjectReference_ReferencedType"; + case PID_TypeDefinitionWeakObjectReference_TargetSet: return "PID_TypeDefinitionWeakObjectReference_TargetSet"; + case PID_TypeDefinitionEnumeration_ElementType: return "PID_TypeDefinitionEnumeration_ElementType"; + case PID_TypeDefinitionEnumeration_ElementNames: return "PID_TypeDefinitionEnumeration_ElementNames"; + case PID_TypeDefinitionEnumeration_ElementValues: return "PID_TypeDefinitionEnumeration_ElementValues"; + case PID_TypeDefinitionFixedArray_ElementType: return "PID_TypeDefinitionFixedArray_ElementType"; + case PID_TypeDefinitionFixedArray_ElementCount: return "PID_TypeDefinitionFixedArray_ElementCount"; + case PID_TypeDefinitionVariableArray_ElementType: return "PID_TypeDefinitionVariableArray_ElementType"; + case PID_TypeDefinitionSet_ElementType: return "PID_TypeDefinitionSet_ElementType"; + case PID_TypeDefinitionString_ElementType: return "PID_TypeDefinitionString_ElementType"; + case PID_TypeDefinitionRecord_MemberTypes: return "PID_TypeDefinitionRecord_MemberTypes"; + case PID_TypeDefinitionRecord_MemberNames: return "PID_TypeDefinitionRecord_MemberNames"; + case PID_TypeDefinitionRename_RenamedType: return "PID_TypeDefinitionRename_RenamedType"; + case PID_TypeDefinitionExtendibleEnumeration_ElementNames: return "PID_TypeDefinitionExtendibleEnumeration_ElementNames"; + case PID_TypeDefinitionExtendibleEnumeration_ElementValues: return "PID_TypeDefinitionExtendibleEnumeration_ElementValues"; + case PID_MetaDefinition_Identification: return "PID_MetaDefinition_Identification"; + case PID_MetaDefinition_Name: return "PID_MetaDefinition_Name"; + case PID_MetaDefinition_Description: return "PID_MetaDefinition_Description"; + case PID_MetaDictionary_ClassDefinitions: return "PID_MetaDictionary_ClassDefinitions"; + case PID_MetaDictionary_TypeDefinitions: return "PID_MetaDictionary_TypeDefinitions"; } - static wchar_t PIDText[1024]; + static char PIDText[1024]; aafClass *Class = NULL; @@ -1267,133 +1390,142 @@ const wchar_t * aaft_PIDToText( AAF_Data *aafd, aafPID_t pid ) foreachPropertyDefinition( PDef, Class->Properties ) { if ( PDef->pid == pid ) { - swprintf( PIDText, 1024, L"%" WPRIs L"%" WPRIws L"%" WPRIs, - (PDef->meta) ? ANSI_COLOR_YELLOW(aafd->dbg) : "", + + int rc = snprintf( PIDText, sizeof(PIDText), "%s%s%s", + (PDef->meta) ? ANSI_COLOR_MAGENTA(aafd->log) : "", PDef->name, - (PDef->meta) ? ANSI_COLOR_RESET(aafd->dbg) : "" ); + (PDef->meta) ? ANSI_COLOR_RESET(aafd->log) : "" ); + + assert( rc >= 0 && (size_t)rc < sizeof(PIDText) ); + + // if ( rc < 0 || (size_t)rc >= 1024 ) { + // fprintf( stderr, "snprintf() error" ); + // return NULL; + // } + return PIDText; } } } - return L"Unknown PID_MetaDictionary"; + return "Unknown PID_MetaDictionary"; } -const wchar_t * aaft_ClassIDToText( AAF_Data *aafd, const aafUID_t *auid ) +const char * aaft_ClassIDToText( AAF_Data *aafd, const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; - - if ( aafUIDCmp( auid, &AUID_NULL ) ) return L"AUID_NULL"; - if ( aafUIDCmp( auid, &AAFClassID_Root ) ) return L"AAFClassID_Root"; - if ( aafUIDCmp( auid, &AAFClassID_InterchangeObject ) ) return L"AAFClassID_InterchangeObject"; - if ( aafUIDCmp( auid, &AAFClassID_Component ) ) return L"AAFClassID_Component"; - if ( aafUIDCmp( auid, &AAFClassID_Segment ) ) return L"AAFClassID_Segment"; - if ( aafUIDCmp( auid, &AAFClassID_EdgeCode ) ) return L"AAFClassID_EdgeCode"; - if ( aafUIDCmp( auid, &AAFClassID_EssenceGroup ) ) return L"AAFClassID_EssenceGroup"; - if ( aafUIDCmp( auid, &AAFClassID_Event ) ) return L"AAFClassID_Event"; - if ( aafUIDCmp( auid, &AAFClassID_GPITrigger ) ) return L"AAFClassID_GPITrigger"; - if ( aafUIDCmp( auid, &AAFClassID_CommentMarker ) ) return L"AAFClassID_CommentMarker"; - if ( aafUIDCmp( auid, &AAFClassID_Filler ) ) return L"AAFClassID_Filler"; - if ( aafUIDCmp( auid, &AAFClassID_OperationGroup ) ) return L"AAFClassID_OperationGroup"; - if ( aafUIDCmp( auid, &AAFClassID_NestedScope ) ) return L"AAFClassID_NestedScope"; - if ( aafUIDCmp( auid, &AAFClassID_Pulldown ) ) return L"AAFClassID_Pulldown"; - if ( aafUIDCmp( auid, &AAFClassID_ScopeReference ) ) return L"AAFClassID_ScopeReference"; - if ( aafUIDCmp( auid, &AAFClassID_Selector ) ) return L"AAFClassID_Selector"; - if ( aafUIDCmp( auid, &AAFClassID_Sequence ) ) return L"AAFClassID_Sequence"; - if ( aafUIDCmp( auid, &AAFClassID_SourceReference ) ) return L"AAFClassID_SourceReference"; - if ( aafUIDCmp( auid, &AAFClassID_SourceClip ) ) return L"AAFClassID_SourceClip"; - if ( aafUIDCmp( auid, &AAFClassID_TextClip ) ) return L"AAFClassID_TextClip"; - if ( aafUIDCmp( auid, &AAFClassID_HTMLClip ) ) return L"AAFClassID_HTMLClip"; - if ( aafUIDCmp( auid, &AAFClassID_Timecode ) ) return L"AAFClassID_Timecode"; - if ( aafUIDCmp( auid, &AAFClassID_TimecodeStream ) ) return L"AAFClassID_TimecodeStream"; - if ( aafUIDCmp( auid, &AAFClassID_TimecodeStream12M ) ) return L"AAFClassID_TimecodeStream12M"; - if ( aafUIDCmp( auid, &AAFClassID_Transition ) ) return L"AAFClassID_Transition"; - if ( aafUIDCmp( auid, &AAFClassID_ContentStorage ) ) return L"AAFClassID_ContentStorage"; - if ( aafUIDCmp( auid, &AAFClassID_ControlPoint ) ) return L"AAFClassID_ControlPoint"; - if ( aafUIDCmp( auid, &AAFClassID_DefinitionObject ) ) return L"AAFClassID_DefinitionObject"; - if ( aafUIDCmp( auid, &AAFClassID_DataDefinition ) ) return L"AAFClassID_DataDefinition"; - if ( aafUIDCmp( auid, &AAFClassID_OperationDefinition ) ) return L"AAFClassID_OperationDefinition"; - if ( aafUIDCmp( auid, &AAFClassID_ParameterDefinition ) ) return L"AAFClassID_ParameterDefinition"; - if ( aafUIDCmp( auid, &AAFClassID_PluginDefinition ) ) return L"AAFClassID_PluginDefinition"; - if ( aafUIDCmp( auid, &AAFClassID_CodecDefinition ) ) return L"AAFClassID_CodecDefinition"; - if ( aafUIDCmp( auid, &AAFClassID_ContainerDefinition ) ) return L"AAFClassID_ContainerDefinition"; - if ( aafUIDCmp( auid, &AAFClassID_InterpolationDefinition ) ) return L"AAFClassID_InterpolationDefinition"; - if ( aafUIDCmp( auid, &AAFClassID_Dictionary ) ) return L"AAFClassID_Dictionary"; - if ( aafUIDCmp( auid, &AAFClassID_EssenceData ) ) return L"AAFClassID_EssenceData"; - if ( aafUIDCmp( auid, &AAFClassID_EssenceDescriptor ) ) return L"AAFClassID_EssenceDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_FileDescriptor ) ) return L"AAFClassID_FileDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_AIFCDescriptor ) ) return L"AAFClassID_AIFCDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_DigitalImageDescriptor ) ) return L"AAFClassID_DigitalImageDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_CDCIDescriptor ) ) return L"AAFClassID_CDCIDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_RGBADescriptor ) ) return L"AAFClassID_RGBADescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_HTMLDescriptor ) ) return L"AAFClassID_HTMLDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_TIFFDescriptor ) ) return L"AAFClassID_TIFFDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_WAVEDescriptor ) ) return L"AAFClassID_WAVEDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_FilmDescriptor ) ) return L"AAFClassID_FilmDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_TapeDescriptor ) ) return L"AAFClassID_TapeDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_Header ) ) return L"AAFClassID_Header"; - if ( aafUIDCmp( auid, &AAFClassID_Identification ) ) return L"AAFClassID_Identification"; - if ( aafUIDCmp( auid, &AAFClassID_Locator ) ) return L"AAFClassID_Locator"; - if ( aafUIDCmp( auid, &AAFClassID_NetworkLocator ) ) return L"AAFClassID_NetworkLocator"; - if ( aafUIDCmp( auid, &AAFClassID_TextLocator ) ) return L"AAFClassID_TextLocator"; - if ( aafUIDCmp( auid, &AAFClassID_Mob ) ) return L"AAFClassID_Mob"; - if ( aafUIDCmp( auid, &AAFClassID_CompositionMob ) ) return L"AAFClassID_CompositionMob"; - if ( aafUIDCmp( auid, &AAFClassID_MasterMob ) ) return L"AAFClassID_MasterMob"; - if ( aafUIDCmp( auid, &AAFClassID_SourceMob ) ) return L"AAFClassID_SourceMob"; - if ( aafUIDCmp( auid, &AAFClassID_MobSlot ) ) return L"AAFClassID_MobSlot"; - if ( aafUIDCmp( auid, &AAFClassID_EventMobSlot ) ) return L"AAFClassID_EventMobSlot"; - if ( aafUIDCmp( auid, &AAFClassID_StaticMobSlot ) ) return L"AAFClassID_StaticMobSlot"; - if ( aafUIDCmp( auid, &AAFClassID_TimelineMobSlot ) ) return L"AAFClassID_TimelineMobSlot"; - if ( aafUIDCmp( auid, &AAFClassID_Parameter ) ) return L"AAFClassID_Parameter"; - if ( aafUIDCmp( auid, &AAFClassID_ConstantValue ) ) return L"AAFClassID_ConstantValue"; - if ( aafUIDCmp( auid, &AAFClassID_VaryingValue ) ) return L"AAFClassID_VaryingValue"; - if ( aafUIDCmp( auid, &AAFClassID_TaggedValue ) ) return L"AAFClassID_TaggedValue"; - if ( aafUIDCmp( auid, &AAFClassID_KLVData ) ) return L"AAFClassID_KLVData"; - if ( aafUIDCmp( auid, &AAFClassID_DescriptiveMarker ) ) return L"AAFClassID_DescriptiveMarker"; - if ( aafUIDCmp( auid, &AAFClassID_SoundDescriptor ) ) return L"AAFClassID_SoundDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_DataEssenceDescriptor ) ) return L"AAFClassID_DataEssenceDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_MultipleDescriptor ) ) return L"AAFClassID_MultipleDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_DescriptiveClip ) ) return L"AAFClassID_DescriptiveClip"; - if ( aafUIDCmp( auid, &AAFClassID_AES3PCMDescriptor ) ) return L"AAFClassID_AES3PCMDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_PCMDescriptor ) ) return L"AAFClassID_PCMDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_PhysicalDescriptor ) ) return L"AAFClassID_PhysicalDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_ImportDescriptor ) ) return L"AAFClassID_ImportDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_RecordingDescriptor ) ) return L"AAFClassID_RecordingDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_TaggedValueDefinition ) ) return L"AAFClassID_TaggedValueDefinition"; - if ( aafUIDCmp( auid, &AAFClassID_KLVDataDefinition ) ) return L"AAFClassID_KLVDataDefinition"; - if ( aafUIDCmp( auid, &AAFClassID_AuxiliaryDescriptor ) ) return L"AAFClassID_AuxiliaryDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_RIFFChunk ) ) return L"AAFClassID_RIFFChunk"; - if ( aafUIDCmp( auid, &AAFClassID_BWFImportDescriptor ) ) return L"AAFClassID_BWFImportDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_MPEGVideoDescriptor ) ) return L"AAFClassID_MPEGVideoDescriptor"; - if ( aafUIDCmp( auid, &AAFClassID_ClassDefinition ) ) return L"AAFClassID_ClassDefinition"; - if ( aafUIDCmp( auid, &AAFClassID_PropertyDefinition ) ) return L"AAFClassID_PropertyDefinition"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinition ) ) return L"AAFClassID_TypeDefinition"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionInteger ) ) return L"AAFClassID_TypeDefinitionInteger"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionStrongObjectReference ) ) return L"AAFClassID_TypeDefinitionStrongObjectReference"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionWeakObjectReference ) ) return L"AAFClassID_TypeDefinitionWeakObjectReference"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionEnumeration ) ) return L"AAFClassID_TypeDefinitionEnumeration"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionFixedArray ) ) return L"AAFClassID_TypeDefinitionFixedArray"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionVariableArray ) ) return L"AAFClassID_TypeDefinitionVariableArray"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionSet ) ) return L"AAFClassID_TypeDefinitionSet"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionString ) ) return L"AAFClassID_TypeDefinitionString"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionStream ) ) return L"AAFClassID_TypeDefinitionStream"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionRecord ) ) return L"AAFClassID_TypeDefinitionRecord"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionRename ) ) return L"AAFClassID_TypeDefinitionRename"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionExtendibleEnumeration ) ) return L"AAFClassID_TypeDefinitionExtendibleEnumeration"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionIndirect ) ) return L"AAFClassID_TypeDefinitionIndirect"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionOpaque ) ) return L"AAFClassID_TypeDefinitionOpaque"; - if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionCharacter ) ) return L"AAFClassID_TypeDefinitionCharacter"; - if ( aafUIDCmp( auid, &AAFClassID_MetaDefinition ) ) return L"AAFClassID_MetaDefinition"; - if ( aafUIDCmp( auid, &AAFClassID_MetaDictionary ) ) return L"AAFClassID_MetaDictionary"; - if ( aafUIDCmp( auid, &AAFClassID_DescriptiveObject ) ) return L"AAFClassID_DescriptiveObject"; - if ( aafUIDCmp( auid, &AAFClassID_DescriptiveFramework ) ) return L"AAFClassID_DescriptiveFramework"; - - - static wchar_t ClassIDText[1024]; + return "n/a"; + + if ( aafUIDCmp( auid, &AUID_NULL ) ) return "AUID_NULL"; + if ( aafUIDCmp( auid, &AAFClassID_Root ) ) return "AAFClassID_Root"; + if ( aafUIDCmp( auid, &AAFClassID_InterchangeObject ) ) return "AAFClassID_InterchangeObject"; + if ( aafUIDCmp( auid, &AAFClassID_Component ) ) return "AAFClassID_Component"; + if ( aafUIDCmp( auid, &AAFClassID_Segment ) ) return "AAFClassID_Segment"; + if ( aafUIDCmp( auid, &AAFClassID_EdgeCode ) ) return "AAFClassID_EdgeCode"; + if ( aafUIDCmp( auid, &AAFClassID_EssenceGroup ) ) return "AAFClassID_EssenceGroup"; + if ( aafUIDCmp( auid, &AAFClassID_Event ) ) return "AAFClassID_Event"; + if ( aafUIDCmp( auid, &AAFClassID_GPITrigger ) ) return "AAFClassID_GPITrigger"; + if ( aafUIDCmp( auid, &AAFClassID_CommentMarker ) ) return "AAFClassID_CommentMarker"; + if ( aafUIDCmp( auid, &AAFClassID_Filler ) ) return "AAFClassID_Filler"; + if ( aafUIDCmp( auid, &AAFClassID_OperationGroup ) ) return "AAFClassID_OperationGroup"; + if ( aafUIDCmp( auid, &AAFClassID_NestedScope ) ) return "AAFClassID_NestedScope"; + if ( aafUIDCmp( auid, &AAFClassID_Pulldown ) ) return "AAFClassID_Pulldown"; + if ( aafUIDCmp( auid, &AAFClassID_ScopeReference ) ) return "AAFClassID_ScopeReference"; + if ( aafUIDCmp( auid, &AAFClassID_Selector ) ) return "AAFClassID_Selector"; + if ( aafUIDCmp( auid, &AAFClassID_Sequence ) ) return "AAFClassID_Sequence"; + if ( aafUIDCmp( auid, &AAFClassID_SourceReference ) ) return "AAFClassID_SourceReference"; + if ( aafUIDCmp( auid, &AAFClassID_SourceClip ) ) return "AAFClassID_SourceClip"; + if ( aafUIDCmp( auid, &AAFClassID_TextClip ) ) return "AAFClassID_TextClip"; + if ( aafUIDCmp( auid, &AAFClassID_HTMLClip ) ) return "AAFClassID_HTMLClip"; + if ( aafUIDCmp( auid, &AAFClassID_Timecode ) ) return "AAFClassID_Timecode"; + if ( aafUIDCmp( auid, &AAFClassID_TimecodeStream ) ) return "AAFClassID_TimecodeStream"; + if ( aafUIDCmp( auid, &AAFClassID_TimecodeStream12M ) ) return "AAFClassID_TimecodeStream12M"; + if ( aafUIDCmp( auid, &AAFClassID_Transition ) ) return "AAFClassID_Transition"; + if ( aafUIDCmp( auid, &AAFClassID_ContentStorage ) ) return "AAFClassID_ContentStorage"; + if ( aafUIDCmp( auid, &AAFClassID_ControlPoint ) ) return "AAFClassID_ControlPoint"; + if ( aafUIDCmp( auid, &AAFClassID_DefinitionObject ) ) return "AAFClassID_DefinitionObject"; + if ( aafUIDCmp( auid, &AAFClassID_DataDefinition ) ) return "AAFClassID_DataDefinition"; + if ( aafUIDCmp( auid, &AAFClassID_OperationDefinition ) ) return "AAFClassID_OperationDefinition"; + if ( aafUIDCmp( auid, &AAFClassID_ParameterDefinition ) ) return "AAFClassID_ParameterDefinition"; + if ( aafUIDCmp( auid, &AAFClassID_PluginDefinition ) ) return "AAFClassID_PluginDefinition"; + if ( aafUIDCmp( auid, &AAFClassID_CodecDefinition ) ) return "AAFClassID_CodecDefinition"; + if ( aafUIDCmp( auid, &AAFClassID_ContainerDefinition ) ) return "AAFClassID_ContainerDefinition"; + if ( aafUIDCmp( auid, &AAFClassID_InterpolationDefinition ) ) return "AAFClassID_InterpolationDefinition"; + if ( aafUIDCmp( auid, &AAFClassID_Dictionary ) ) return "AAFClassID_Dictionary"; + if ( aafUIDCmp( auid, &AAFClassID_EssenceData ) ) return "AAFClassID_EssenceData"; + if ( aafUIDCmp( auid, &AAFClassID_EssenceDescriptor ) ) return "AAFClassID_EssenceDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_FileDescriptor ) ) return "AAFClassID_FileDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_AIFCDescriptor ) ) return "AAFClassID_AIFCDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_DigitalImageDescriptor ) ) return "AAFClassID_DigitalImageDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_CDCIDescriptor ) ) return "AAFClassID_CDCIDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_RGBADescriptor ) ) return "AAFClassID_RGBADescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_HTMLDescriptor ) ) return "AAFClassID_HTMLDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_TIFFDescriptor ) ) return "AAFClassID_TIFFDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_WAVEDescriptor ) ) return "AAFClassID_WAVEDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_FilmDescriptor ) ) return "AAFClassID_FilmDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_TapeDescriptor ) ) return "AAFClassID_TapeDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_Header ) ) return "AAFClassID_Header"; + if ( aafUIDCmp( auid, &AAFClassID_Identification ) ) return "AAFClassID_Identification"; + if ( aafUIDCmp( auid, &AAFClassID_Locator ) ) return "AAFClassID_Locator"; + if ( aafUIDCmp( auid, &AAFClassID_NetworkLocator ) ) return "AAFClassID_NetworkLocator"; + if ( aafUIDCmp( auid, &AAFClassID_TextLocator ) ) return "AAFClassID_TextLocator"; + if ( aafUIDCmp( auid, &AAFClassID_Mob ) ) return "AAFClassID_Mob"; + if ( aafUIDCmp( auid, &AAFClassID_CompositionMob ) ) return "AAFClassID_CompositionMob"; + if ( aafUIDCmp( auid, &AAFClassID_MasterMob ) ) return "AAFClassID_MasterMob"; + if ( aafUIDCmp( auid, &AAFClassID_SourceMob ) ) return "AAFClassID_SourceMob"; + if ( aafUIDCmp( auid, &AAFClassID_MobSlot ) ) return "AAFClassID_MobSlot"; + if ( aafUIDCmp( auid, &AAFClassID_EventMobSlot ) ) return "AAFClassID_EventMobSlot"; + if ( aafUIDCmp( auid, &AAFClassID_StaticMobSlot ) ) return "AAFClassID_StaticMobSlot"; + if ( aafUIDCmp( auid, &AAFClassID_TimelineMobSlot ) ) return "AAFClassID_TimelineMobSlot"; + if ( aafUIDCmp( auid, &AAFClassID_Parameter ) ) return "AAFClassID_Parameter"; + if ( aafUIDCmp( auid, &AAFClassID_ConstantValue ) ) return "AAFClassID_ConstantValue"; + if ( aafUIDCmp( auid, &AAFClassID_VaryingValue ) ) return "AAFClassID_VaryingValue"; + if ( aafUIDCmp( auid, &AAFClassID_TaggedValue ) ) return "AAFClassID_TaggedValue"; + if ( aafUIDCmp( auid, &AAFClassID_KLVData ) ) return "AAFClassID_KLVData"; + if ( aafUIDCmp( auid, &AAFClassID_DescriptiveMarker ) ) return "AAFClassID_DescriptiveMarker"; + if ( aafUIDCmp( auid, &AAFClassID_SoundDescriptor ) ) return "AAFClassID_SoundDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_DataEssenceDescriptor ) ) return "AAFClassID_DataEssenceDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_MultipleDescriptor ) ) return "AAFClassID_MultipleDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_DescriptiveClip ) ) return "AAFClassID_DescriptiveClip"; + if ( aafUIDCmp( auid, &AAFClassID_AES3PCMDescriptor ) ) return "AAFClassID_AES3PCMDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_PCMDescriptor ) ) return "AAFClassID_PCMDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_PhysicalDescriptor ) ) return "AAFClassID_PhysicalDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_ImportDescriptor ) ) return "AAFClassID_ImportDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_RecordingDescriptor ) ) return "AAFClassID_RecordingDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_TaggedValueDefinition ) ) return "AAFClassID_TaggedValueDefinition"; + if ( aafUIDCmp( auid, &AAFClassID_KLVDataDefinition ) ) return "AAFClassID_KLVDataDefinition"; + if ( aafUIDCmp( auid, &AAFClassID_AuxiliaryDescriptor ) ) return "AAFClassID_AuxiliaryDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_RIFFChunk ) ) return "AAFClassID_RIFFChunk"; + if ( aafUIDCmp( auid, &AAFClassID_BWFImportDescriptor ) ) return "AAFClassID_BWFImportDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_MPEGVideoDescriptor ) ) return "AAFClassID_MPEGVideoDescriptor"; + if ( aafUIDCmp( auid, &AAFClassID_ClassDefinition ) ) return "AAFClassID_ClassDefinition"; + if ( aafUIDCmp( auid, &AAFClassID_PropertyDefinition ) ) return "AAFClassID_PropertyDefinition"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinition ) ) return "AAFClassID_TypeDefinition"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionInteger ) ) return "AAFClassID_TypeDefinitionInteger"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionStrongObjectReference ) ) return "AAFClassID_TypeDefinitionStrongObjectReference"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionWeakObjectReference ) ) return "AAFClassID_TypeDefinitionWeakObjectReference"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionEnumeration ) ) return "AAFClassID_TypeDefinitionEnumeration"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionFixedArray ) ) return "AAFClassID_TypeDefinitionFixedArray"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionVariableArray ) ) return "AAFClassID_TypeDefinitionVariableArray"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionSet ) ) return "AAFClassID_TypeDefinitionSet"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionString ) ) return "AAFClassID_TypeDefinitionString"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionStream ) ) return "AAFClassID_TypeDefinitionStream"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionRecord ) ) return "AAFClassID_TypeDefinitionRecord"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionRename ) ) return "AAFClassID_TypeDefinitionRename"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionExtendibleEnumeration ) ) return "AAFClassID_TypeDefinitionExtendibleEnumeration"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionIndirect ) ) return "AAFClassID_TypeDefinitionIndirect"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionOpaque ) ) return "AAFClassID_TypeDefinitionOpaque"; + if ( aafUIDCmp( auid, &AAFClassID_TypeDefinitionCharacter ) ) return "AAFClassID_TypeDefinitionCharacter"; + if ( aafUIDCmp( auid, &AAFClassID_MetaDefinition ) ) return "AAFClassID_MetaDefinition"; + if ( aafUIDCmp( auid, &AAFClassID_MetaDictionary ) ) return "AAFClassID_MetaDictionary"; + if ( aafUIDCmp( auid, &AAFClassID_DescriptiveObject ) ) return "AAFClassID_DescriptiveObject"; + if ( aafUIDCmp( auid, &AAFClassID_DescriptiveFramework ) ) return "AAFClassID_DescriptiveFramework"; + + + static char ClassIDText[1024]; ClassIDText[0] = '\0'; @@ -1402,152 +1534,217 @@ const wchar_t * aaft_ClassIDToText( AAF_Data *aafd, const aafUID_t *auid ) foreachClass( Class, aafd->Classes ) { if ( aafUIDCmp( Class->ID, auid ) ) { - swprintf( ClassIDText, 1024, L"%" WPRIs L"%" WPRIws L"%" WPRIs, - (Class->meta) ? ANSI_COLOR_YELLOW(aafd->dbg) : "", + + int rc = snprintf( ClassIDText, sizeof(ClassIDText), "%s%s%s", + (Class->meta) ? ANSI_COLOR_MAGENTA(aafd->log) : "", Class->name, - (Class->meta) ? ANSI_COLOR_RESET(aafd->dbg) : "" ); + (Class->meta) ? ANSI_COLOR_RESET(aafd->log) : "" ); + + assert( rc >= 0 && (size_t)rc < sizeof(ClassIDText) ); + + // if ( rc < 0 || (size_t)rc >= 1024 ) { + // fprintf( stderr, "snprintf() error" ); + // return NULL; + // } + return ClassIDText; } } - return L"Unknown AAFClassID"; + return "Unknown AAFClassID"; +} + + + +const char * aaft_IndirectValueToText( AAF_Data *aafd, aafIndirect_t *Indirect ) +{ + static char buf[4096]; + + memset( buf, 0x00, sizeof(buf) ); + + void *indirectValue = aaf_get_indirectValue( aafd, Indirect, NULL ); + + if ( !indirectValue ) { + return NULL; + } + + int rc = 0; + + if ( aafUIDCmp( &Indirect->TypeDef, &AAFTypeID_Boolean ) ) { rc = snprintf( buf, sizeof(buf), "%c", *(uint8_t*)indirectValue ); } + else if ( aafUIDCmp( &Indirect->TypeDef, &AAFTypeID_Rational ) ) { rc = snprintf( buf, sizeof(buf), "%i/%i", ((aafRational_t*)indirectValue)->numerator, ((aafRational_t*)indirectValue)->denominator ); } + + else if ( aafUIDCmp( &Indirect->TypeDef, &AAFTypeID_Int8 ) ) { rc = snprintf( buf, sizeof(buf), "%c", *(int8_t*)indirectValue ); } + else if ( aafUIDCmp( &Indirect->TypeDef, &AAFTypeID_Int16 ) ) { rc = snprintf( buf, sizeof(buf), "%i", *(int16_t*)indirectValue ); } + else if ( aafUIDCmp( &Indirect->TypeDef, &AAFTypeID_Int32 ) ) { rc = snprintf( buf, sizeof(buf), "%i", *(int32_t*)indirectValue ); } + else if ( aafUIDCmp( &Indirect->TypeDef, &AAFTypeID_Int64 ) ) { rc = snprintf( buf, sizeof(buf), "%"PRIi64, *(int64_t*)indirectValue ); } + + else if ( aafUIDCmp( &Indirect->TypeDef, &AAFTypeID_UInt16 ) ) { rc = snprintf( buf, sizeof(buf), "%u", *(uint16_t*)indirectValue ); } + else if ( aafUIDCmp( &Indirect->TypeDef, &AAFTypeID_UInt32 ) ) { rc = snprintf( buf, sizeof(buf), "%u", *(uint32_t*)indirectValue ); } + else if ( aafUIDCmp( &Indirect->TypeDef, &AAFTypeID_UInt64 ) ) { rc = snprintf( buf, sizeof(buf), "%"PRIu64, *(uint64_t*)indirectValue ); } + + else if ( aafUIDCmp( &Indirect->TypeDef, &AAFTypeID_String ) ) { + + char *str = aaf_get_indirectValue( aafd, Indirect, &AAFTypeID_String ); + + if ( !str ) { + error( "Could not retrieve Indirect value" ); + return NULL; + } + + rc = snprintf( buf, sizeof(buf), "%s", str ); + + free( str ); + } + else { + error( "Unsupported Indirect value type ID : %s", aaft_TypeIDToText( &Indirect->TypeDef ) ); + return NULL; + } + + assert( rc >= 0 && (size_t)rc < sizeof(buf) ); + + // if ( rc < 0 || (size_t)rc >= sizeof(buf) ) { + // fprintf( stderr, "snprintf() error" ); + // return NULL; + // } + + return buf; } -const wchar_t * aaft_ContainerToText( const aafUID_t *auid ) +const char * aaft_ContainerToText( const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; - - if ( aafUIDCmp( auid, &AUID_NULL ) ) return L"AUID_NULL"; - if ( aafUIDCmp( auid, &AAFContainerDef_External ) ) return L"AAFContainerDef_External"; - if ( aafUIDCmp( auid, &AAFContainerDef_OMF ) ) return L"AAFContainerDef_OMF"; - if ( aafUIDCmp( auid, &AAFContainerDef_AAF ) ) return L"AAFContainerDef_AAF"; - if ( aafUIDCmp( auid, &AAFContainerDef_AAFMSS ) ) return L"AAFContainerDef_AAFMSS"; - if ( aafUIDCmp( auid, &AAFContainerDef_AAFKLV ) ) return L"AAFContainerDef_AAFKLV"; - if ( aafUIDCmp( auid, &AAFContainerDef_AAFXML ) ) return L"AAFContainerDef_AAFXML"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_50Mbps_DefinedTemplate ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_50Mbps_DefinedTemplate"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_50Mbps_ExtendedTemplate ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_50Mbps_ExtendedTemplate"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_50Mbps_PictureOnly ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_50Mbps_PictureOnly"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_50Mbps_DefinedTemplate ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_50Mbps_DefinedTemplate"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_50Mbps_ExtendedTemplate ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_50Mbps_ExtendedTemplate"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_50Mbps_PictureOnly ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_50Mbps_PictureOnly"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_40Mbps_DefinedTemplate ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_40Mbps_DefinedTemplate"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_40Mbps_ExtendedTemplate ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_40Mbps_ExtendedTemplate"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_40Mbps_PictureOnly ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_40Mbps_PictureOnly"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_40Mbps_DefinedTemplate ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_40Mbps_DefinedTemplate"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_40Mbps_ExtendedTemplate ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_40Mbps_ExtendedTemplate"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_40Mbps_PictureOnly ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_40Mbps_PictureOnly"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_30Mbps_DefinedTemplate ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_30Mbps_DefinedTemplate"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_30Mbps_ExtendedTemplate ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_30Mbps_ExtendedTemplate"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_30Mbps_PictureOnly ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_30Mbps_PictureOnly"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_30Mbps_DefinedTemplate ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_30Mbps_DefinedTemplate"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_30Mbps_ExtendedTemplate ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_30Mbps_ExtendedTemplate"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_30Mbps_PictureOnly ) ) return L"AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_30Mbps_PictureOnly"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_IECDV_525x5994I_25Mbps ) ) return L"AAFContainerDef_MXFGC_Framewrapped_IECDV_525x5994I_25Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_IECDV_525x5994I_25Mbps ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_IECDV_525x5994I_25Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_IECDV_625x50I_25Mbps ) ) return L"AAFContainerDef_MXFGC_Framewrapped_IECDV_625x50I_25Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_IECDV_625x50I_25Mbps ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_IECDV_625x50I_25Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_IECDV_525x5994I_25Mbps_SMPTE322M ) ) return L"AAFContainerDef_MXFGC_Framewrapped_IECDV_525x5994I_25Mbps_SMPTE322M"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_IECDV_525x5994I_25Mbps_SMPTE322M ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_IECDV_525x5994I_25Mbps_SMPTE322M"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_IECDV_625x50I_25Mbps_SMPTE322M ) ) return L"AAFContainerDef_MXFGC_Framewrapped_IECDV_625x50I_25Mbps_SMPTE322M"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_IECDV_625x50I_25Mbps_SMPTE322M ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_IECDV_625x50I_25Mbps_SMPTE322M"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_IECDV_UndefinedSource_25Mbps ) ) return L"AAFContainerDef_MXFGC_Framewrapped_IECDV_UndefinedSource_25Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_IECDV_UndefinedSource_25Mbps ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_IECDV_UndefinedSource_25Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_525x5994I_25Mbps ) ) return L"AAFContainerDef_MXFGC_Framewrapped_DVbased_525x5994I_25Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_525x5994I_25Mbps ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_DVbased_525x5994I_25Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_625x50I_25Mbps ) ) return L"AAFContainerDef_MXFGC_Framewrapped_DVbased_625x50I_25Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_625x50I_25Mbps ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_DVbased_625x50I_25Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_525x5994I_50Mbps ) ) return L"AAFContainerDef_MXFGC_Framewrapped_DVbased_525x5994I_50Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_525x5994I_50Mbps ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_DVbased_525x5994I_50Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_625x50I_50Mbps ) ) return L"AAFContainerDef_MXFGC_Framewrapped_DVbased_625x50I_50Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_625x50I_50Mbps ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_DVbased_625x50I_50Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_1080x5994I_100Mbps ) ) return L"AAFContainerDef_MXFGC_Framewrapped_DVbased_1080x5994I_100Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_1080x5994I_100Mbps ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_DVbased_1080x5994I_100Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_1080x50I_100Mbps ) ) return L"AAFContainerDef_MXFGC_Framewrapped_DVbased_1080x50I_100Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_1080x50I_100Mbps ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_DVbased_1080x50I_100Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_720x5994P_100Mbps ) ) return L"AAFContainerDef_MXFGC_Framewrapped_DVbased_720x5994P_100Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_720x5994P_100Mbps ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_DVbased_720x5994P_100Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_720x50P_100Mbps ) ) return L"AAFContainerDef_MXFGC_Framewrapped_DVbased_720x50P_100Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_720x50P_100Mbps ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_DVbased_720x50P_100Mbps"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_UndefinedSource ) ) return L"AAFContainerDef_MXFGC_Framewrapped_DVbased_UndefinedSource"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_UndefinedSource ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_DVbased_UndefinedSource"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_MPEGES_VideoStream0_SID ) ) return L"AAFContainerDef_MXFGC_Framewrapped_MPEGES_VideoStream0_SID"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_CustomClosedGOPwrapped_MPEGES_VideoStream1_SID ) ) return L"AAFContainerDef_MXFGC_CustomClosedGOPwrapped_MPEGES_VideoStream1_SID"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_Uncompressed_525x5994I_720_422 ) ) return L"AAFContainerDef_MXFGC_Framewrapped_Uncompressed_525x5994I_720_422"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_525x5994I_720_422 ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_525x5994I_720_422"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Linewrapped_Uncompressed_525x5994I_720_422 ) ) return L"AAFContainerDef_MXFGC_Linewrapped_Uncompressed_525x5994I_720_422"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_Uncompressed_625x50I_720_422 ) ) return L"AAFContainerDef_MXFGC_Framewrapped_Uncompressed_625x50I_720_422"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_625x50I_720_422 ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_625x50I_720_422"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Linewrapped_Uncompressed_625x50I_720_422 ) ) return L"AAFContainerDef_MXFGC_Linewrapped_Uncompressed_625x50I_720_422"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_Uncompressed_525x5994P_960_422 ) ) return L"AAFContainerDef_MXFGC_Framewrapped_Uncompressed_525x5994P_960_422"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_525x5994P_960_422 ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_525x5994P_960_422"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Linewrapped_Uncompressed_525x5994P_960_422 ) ) return L"AAFContainerDef_MXFGC_Linewrapped_Uncompressed_525x5994P_960_422"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_Uncompressed_625x50P_960_422 ) ) return L"AAFContainerDef_MXFGC_Framewrapped_Uncompressed_625x50P_960_422"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_625x50P_960_422 ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_625x50P_960_422"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Linewrapped_Uncompressed_625x50P_960_422 ) ) return L"AAFContainerDef_MXFGC_Linewrapped_Uncompressed_625x50P_960_422"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_Broadcast_Wave_audio_data ) ) return L"AAFContainerDef_MXFGC_Framewrapped_Broadcast_Wave_audio_data"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_Broadcast_Wave_audio_data ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_Broadcast_Wave_audio_data"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_AES3_audio_data ) ) return L"AAFContainerDef_MXFGC_Framewrapped_AES3_audio_data"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_AES3_audio_data ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_AES3_audio_data"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_Alaw_Audio ) ) return L"AAFContainerDef_MXFGC_Framewrapped_Alaw_Audio"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_Alaw_Audio ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_Alaw_Audio"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Customwrapped_Alaw_Audio ) ) return L"AAFContainerDef_MXFGC_Customwrapped_Alaw_Audio"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_AVCbytestream_VideoStream0_SID ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_AVCbytestream_VideoStream0_SID"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_VC3 ) ) return L"AAFContainerDef_MXFGC_Framewrapped_VC3"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_VC3 ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_VC3"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_VC1 ) ) return L"AAFContainerDef_MXFGC_Framewrapped_VC1"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_VC1 ) ) return L"AAFContainerDef_MXFGC_Clipwrapped_VC1"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Generic_Essence_Multiple_Mappings ) ) return L"AAFContainerDef_MXFGC_Generic_Essence_Multiple_Mappings"; - if ( aafUIDCmp( auid, &AAFContainerDef_RIFFWAVE ) ) return L"AAFContainerDef_RIFFWAVE"; - if ( aafUIDCmp( auid, &AAFContainerDef_JFIF ) ) return L"AAFContainerDef_JFIF"; - if ( aafUIDCmp( auid, &AAFContainerDef_AIFFAIFC ) ) return L"AAFContainerDef_AIFFAIFC"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_220X_1080p ) ) return L"AAFContainerDef_MXFGC_Avid_DNX_220X_1080p"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_145_1080p ) ) return L"AAFContainerDef_MXFGC_Avid_DNX_145_1080p"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_220_1080p ) ) return L"AAFContainerDef_MXFGC_Avid_DNX_220_1080p"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_36_1080p ) ) return L"AAFContainerDef_MXFGC_Avid_DNX_36_1080p"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_220X_1080i ) ) return L"AAFContainerDef_MXFGC_Avid_DNX_220X_1080i"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_145_1080i ) ) return L"AAFContainerDef_MXFGC_Avid_DNX_145_1080i"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_220_1080i ) ) return L"AAFContainerDef_MXFGC_Avid_DNX_220_1080i"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_145_1440_1080i ) ) return L"AAFContainerDef_MXFGC_Avid_DNX_145_1440_1080i"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_220X_720p ) ) return L"AAFContainerDef_MXFGC_Avid_DNX_220X_720p"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_220_720p ) ) return L"AAFContainerDef_MXFGC_Avid_DNX_220_720p"; - if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_145_720p ) ) return L"AAFContainerDef_MXFGC_Avid_DNX_145_720p"; - - return L"Unknown AAFContainerDef"; + return "n/a"; + + if ( aafUIDCmp( auid, &AUID_NULL ) ) return "AUID_NULL"; + if ( aafUIDCmp( auid, &AAFContainerDef_External ) ) return "AAFContainerDef_External"; + if ( aafUIDCmp( auid, &AAFContainerDef_OMF ) ) return "AAFContainerDef_OMF"; + if ( aafUIDCmp( auid, &AAFContainerDef_AAF ) ) return "AAFContainerDef_AAF"; + if ( aafUIDCmp( auid, &AAFContainerDef_AAFMSS ) ) return "AAFContainerDef_AAFMSS"; + if ( aafUIDCmp( auid, &AAFContainerDef_AAFKLV ) ) return "AAFContainerDef_AAFKLV"; + if ( aafUIDCmp( auid, &AAFContainerDef_AAFXML ) ) return "AAFContainerDef_AAFXML"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_50Mbps_DefinedTemplate ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_50Mbps_DefinedTemplate"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_50Mbps_ExtendedTemplate ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_50Mbps_ExtendedTemplate"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_50Mbps_PictureOnly ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_50Mbps_PictureOnly"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_50Mbps_DefinedTemplate ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_50Mbps_DefinedTemplate"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_50Mbps_ExtendedTemplate ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_50Mbps_ExtendedTemplate"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_50Mbps_PictureOnly ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_50Mbps_PictureOnly"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_40Mbps_DefinedTemplate ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_40Mbps_DefinedTemplate"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_40Mbps_ExtendedTemplate ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_40Mbps_ExtendedTemplate"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_40Mbps_PictureOnly ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_40Mbps_PictureOnly"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_40Mbps_DefinedTemplate ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_40Mbps_DefinedTemplate"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_40Mbps_ExtendedTemplate ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_40Mbps_ExtendedTemplate"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_40Mbps_PictureOnly ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_40Mbps_PictureOnly"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_30Mbps_DefinedTemplate ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_30Mbps_DefinedTemplate"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_30Mbps_ExtendedTemplate ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_30Mbps_ExtendedTemplate"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_30Mbps_PictureOnly ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_625x50I_30Mbps_PictureOnly"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_30Mbps_DefinedTemplate ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_30Mbps_DefinedTemplate"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_30Mbps_ExtendedTemplate ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_30Mbps_ExtendedTemplate"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_30Mbps_PictureOnly ) ) return "AAFContainerDef_MXFGC_Framewrapped_SMPTE_D10_525x5994I_30Mbps_PictureOnly"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_IECDV_525x5994I_25Mbps ) ) return "AAFContainerDef_MXFGC_Framewrapped_IECDV_525x5994I_25Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_IECDV_525x5994I_25Mbps ) ) return "AAFContainerDef_MXFGC_Clipwrapped_IECDV_525x5994I_25Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_IECDV_625x50I_25Mbps ) ) return "AAFContainerDef_MXFGC_Framewrapped_IECDV_625x50I_25Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_IECDV_625x50I_25Mbps ) ) return "AAFContainerDef_MXFGC_Clipwrapped_IECDV_625x50I_25Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_IECDV_525x5994I_25Mbps_SMPTE322M ) ) return "AAFContainerDef_MXFGC_Framewrapped_IECDV_525x5994I_25Mbps_SMPTE322M"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_IECDV_525x5994I_25Mbps_SMPTE322M ) ) return "AAFContainerDef_MXFGC_Clipwrapped_IECDV_525x5994I_25Mbps_SMPTE322M"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_IECDV_625x50I_25Mbps_SMPTE322M ) ) return "AAFContainerDef_MXFGC_Framewrapped_IECDV_625x50I_25Mbps_SMPTE322M"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_IECDV_625x50I_25Mbps_SMPTE322M ) ) return "AAFContainerDef_MXFGC_Clipwrapped_IECDV_625x50I_25Mbps_SMPTE322M"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_IECDV_UndefinedSource_25Mbps ) ) return "AAFContainerDef_MXFGC_Framewrapped_IECDV_UndefinedSource_25Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_IECDV_UndefinedSource_25Mbps ) ) return "AAFContainerDef_MXFGC_Clipwrapped_IECDV_UndefinedSource_25Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_525x5994I_25Mbps ) ) return "AAFContainerDef_MXFGC_Framewrapped_DVbased_525x5994I_25Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_525x5994I_25Mbps ) ) return "AAFContainerDef_MXFGC_Clipwrapped_DVbased_525x5994I_25Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_625x50I_25Mbps ) ) return "AAFContainerDef_MXFGC_Framewrapped_DVbased_625x50I_25Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_625x50I_25Mbps ) ) return "AAFContainerDef_MXFGC_Clipwrapped_DVbased_625x50I_25Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_525x5994I_50Mbps ) ) return "AAFContainerDef_MXFGC_Framewrapped_DVbased_525x5994I_50Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_525x5994I_50Mbps ) ) return "AAFContainerDef_MXFGC_Clipwrapped_DVbased_525x5994I_50Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_625x50I_50Mbps ) ) return "AAFContainerDef_MXFGC_Framewrapped_DVbased_625x50I_50Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_625x50I_50Mbps ) ) return "AAFContainerDef_MXFGC_Clipwrapped_DVbased_625x50I_50Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_1080x5994I_100Mbps ) ) return "AAFContainerDef_MXFGC_Framewrapped_DVbased_1080x5994I_100Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_1080x5994I_100Mbps ) ) return "AAFContainerDef_MXFGC_Clipwrapped_DVbased_1080x5994I_100Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_1080x50I_100Mbps ) ) return "AAFContainerDef_MXFGC_Framewrapped_DVbased_1080x50I_100Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_1080x50I_100Mbps ) ) return "AAFContainerDef_MXFGC_Clipwrapped_DVbased_1080x50I_100Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_720x5994P_100Mbps ) ) return "AAFContainerDef_MXFGC_Framewrapped_DVbased_720x5994P_100Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_720x5994P_100Mbps ) ) return "AAFContainerDef_MXFGC_Clipwrapped_DVbased_720x5994P_100Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_720x50P_100Mbps ) ) return "AAFContainerDef_MXFGC_Framewrapped_DVbased_720x50P_100Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_720x50P_100Mbps ) ) return "AAFContainerDef_MXFGC_Clipwrapped_DVbased_720x50P_100Mbps"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_DVbased_UndefinedSource ) ) return "AAFContainerDef_MXFGC_Framewrapped_DVbased_UndefinedSource"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_DVbased_UndefinedSource ) ) return "AAFContainerDef_MXFGC_Clipwrapped_DVbased_UndefinedSource"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_MPEGES_VideoStream0_SID ) ) return "AAFContainerDef_MXFGC_Framewrapped_MPEGES_VideoStream0_SID"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_CustomClosedGOPwrapped_MPEGES_VideoStream1_SID ) ) return "AAFContainerDef_MXFGC_CustomClosedGOPwrapped_MPEGES_VideoStream1_SID"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_Uncompressed_525x5994I_720_422 ) ) return "AAFContainerDef_MXFGC_Framewrapped_Uncompressed_525x5994I_720_422"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_525x5994I_720_422 ) ) return "AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_525x5994I_720_422"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Linewrapped_Uncompressed_525x5994I_720_422 ) ) return "AAFContainerDef_MXFGC_Linewrapped_Uncompressed_525x5994I_720_422"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_Uncompressed_625x50I_720_422 ) ) return "AAFContainerDef_MXFGC_Framewrapped_Uncompressed_625x50I_720_422"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_625x50I_720_422 ) ) return "AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_625x50I_720_422"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Linewrapped_Uncompressed_625x50I_720_422 ) ) return "AAFContainerDef_MXFGC_Linewrapped_Uncompressed_625x50I_720_422"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_Uncompressed_525x5994P_960_422 ) ) return "AAFContainerDef_MXFGC_Framewrapped_Uncompressed_525x5994P_960_422"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_525x5994P_960_422 ) ) return "AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_525x5994P_960_422"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Linewrapped_Uncompressed_525x5994P_960_422 ) ) return "AAFContainerDef_MXFGC_Linewrapped_Uncompressed_525x5994P_960_422"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_Uncompressed_625x50P_960_422 ) ) return "AAFContainerDef_MXFGC_Framewrapped_Uncompressed_625x50P_960_422"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_625x50P_960_422 ) ) return "AAFContainerDef_MXFGC_Clipwrapped_Uncompressed_625x50P_960_422"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Linewrapped_Uncompressed_625x50P_960_422 ) ) return "AAFContainerDef_MXFGC_Linewrapped_Uncompressed_625x50P_960_422"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_Broadcast_Wave_audio_data ) ) return "AAFContainerDef_MXFGC_Framewrapped_Broadcast_Wave_audio_data"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_Broadcast_Wave_audio_data ) ) return "AAFContainerDef_MXFGC_Clipwrapped_Broadcast_Wave_audio_data"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_AES3_audio_data ) ) return "AAFContainerDef_MXFGC_Framewrapped_AES3_audio_data"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_AES3_audio_data ) ) return "AAFContainerDef_MXFGC_Clipwrapped_AES3_audio_data"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_Alaw_Audio ) ) return "AAFContainerDef_MXFGC_Framewrapped_Alaw_Audio"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_Alaw_Audio ) ) return "AAFContainerDef_MXFGC_Clipwrapped_Alaw_Audio"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Customwrapped_Alaw_Audio ) ) return "AAFContainerDef_MXFGC_Customwrapped_Alaw_Audio"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_AVCbytestream_VideoStream0_SID ) ) return "AAFContainerDef_MXFGC_Clipwrapped_AVCbytestream_VideoStream0_SID"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_VC3 ) ) return "AAFContainerDef_MXFGC_Framewrapped_VC3"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_VC3 ) ) return "AAFContainerDef_MXFGC_Clipwrapped_VC3"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Framewrapped_VC1 ) ) return "AAFContainerDef_MXFGC_Framewrapped_VC1"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Clipwrapped_VC1 ) ) return "AAFContainerDef_MXFGC_Clipwrapped_VC1"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Generic_Essence_Multiple_Mappings ) ) return "AAFContainerDef_MXFGC_Generic_Essence_Multiple_Mappings"; + if ( aafUIDCmp( auid, &AAFContainerDef_RIFFWAVE ) ) return "AAFContainerDef_RIFFWAVE"; + if ( aafUIDCmp( auid, &AAFContainerDef_JFIF ) ) return "AAFContainerDef_JFIF"; + if ( aafUIDCmp( auid, &AAFContainerDef_AIFFAIFC ) ) return "AAFContainerDef_AIFFAIFC"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_220X_1080p ) ) return "AAFContainerDef_MXFGC_Avid_DNX_220X_1080p"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_145_1080p ) ) return "AAFContainerDef_MXFGC_Avid_DNX_145_1080p"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_220_1080p ) ) return "AAFContainerDef_MXFGC_Avid_DNX_220_1080p"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_36_1080p ) ) return "AAFContainerDef_MXFGC_Avid_DNX_36_1080p"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_220X_1080i ) ) return "AAFContainerDef_MXFGC_Avid_DNX_220X_1080i"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_145_1080i ) ) return "AAFContainerDef_MXFGC_Avid_DNX_145_1080i"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_220_1080i ) ) return "AAFContainerDef_MXFGC_Avid_DNX_220_1080i"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_145_1440_1080i ) ) return "AAFContainerDef_MXFGC_Avid_DNX_145_1440_1080i"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_220X_720p ) ) return "AAFContainerDef_MXFGC_Avid_DNX_220X_720p"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_220_720p ) ) return "AAFContainerDef_MXFGC_Avid_DNX_220_720p"; + if ( aafUIDCmp( auid, &AAFContainerDef_MXFGC_Avid_DNX_145_720p ) ) return "AAFContainerDef_MXFGC_Avid_DNX_145_720p"; + + return "Unknown AAFContainerDef"; } -const wchar_t * aaft_CompressionToText( const aafUID_t *auid ) +const char * aaft_CompressionToText( const aafUID_t *auid ) { if ( auid == NULL ) - return L"n/a"; - - if ( aafUIDCmp( auid, &AUID_NULL ) ) return L"AUID_NULL"; - if ( aafUIDCmp( auid, &AAFCompressionDef_AAF_CMPR_FULL_JPEG ) ) return L"AAFCompressionDef_AAF_CMPR_FULL_JPEG"; - if ( aafUIDCmp( auid, &AAFCompressionDef_AAF_CMPR_AUNC422 ) ) return L"AAFCompressionDef_AAF_CMPR_AUNC422"; - if ( aafUIDCmp( auid, &AAFCompressionDef_LegacyDV ) ) return L"AAFCompressionDef_LegacyDV"; - if ( aafUIDCmp( auid, &AAFCompressionDef_SMPTE_D10_50Mbps_625x50I ) ) return L"AAFCompressionDef_SMPTE_D10_50Mbps_625x50I"; - if ( aafUIDCmp( auid, &AAFCompressionDef_SMPTE_D10_50Mbps_525x5994I ) ) return L"AAFCompressionDef_SMPTE_D10_50Mbps_525x5994I"; - if ( aafUIDCmp( auid, &AAFCompressionDef_SMPTE_D10_40Mbps_625x50I ) ) return L"AAFCompressionDef_SMPTE_D10_40Mbps_625x50I"; - if ( aafUIDCmp( auid, &AAFCompressionDef_SMPTE_D10_40Mbps_525x5994I ) ) return L"AAFCompressionDef_SMPTE_D10_40Mbps_525x5994I"; - if ( aafUIDCmp( auid, &AAFCompressionDef_SMPTE_D10_30Mbps_625x50I ) ) return L"AAFCompressionDef_SMPTE_D10_30Mbps_625x50I"; - if ( aafUIDCmp( auid, &AAFCompressionDef_SMPTE_D10_30Mbps_525x5994I ) ) return L"AAFCompressionDef_SMPTE_D10_30Mbps_525x5994I"; - if ( aafUIDCmp( auid, &AAFCompressionDef_IEC_DV_525_60 ) ) return L"AAFCompressionDef_IEC_DV_525_60"; - if ( aafUIDCmp( auid, &AAFCompressionDef_IEC_DV_625_50 ) ) return L"AAFCompressionDef_IEC_DV_625_50"; - if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_25Mbps_525_60 ) ) return L"AAFCompressionDef_DV_Based_25Mbps_525_60"; - if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_25Mbps_625_50 ) ) return L"AAFCompressionDef_DV_Based_25Mbps_625_50"; - if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_50Mbps_525_60 ) ) return L"AAFCompressionDef_DV_Based_50Mbps_525_60"; - if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_50Mbps_625_50 ) ) return L"AAFCompressionDef_DV_Based_50Mbps_625_50"; - if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_100Mbps_1080x5994I ) ) return L"AAFCompressionDef_DV_Based_100Mbps_1080x5994I"; - if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_100Mbps_1080x50I ) ) return L"AAFCompressionDef_DV_Based_100Mbps_1080x50I"; - if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_100Mbps_720x5994P ) ) return L"AAFCompressionDef_DV_Based_100Mbps_720x5994P"; - if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_100Mbps_720x50P ) ) return L"AAFCompressionDef_DV_Based_100Mbps_720x50P"; - if ( aafUIDCmp( auid, &AAFCompressionDef_VC3_1 ) ) return L"AAFCompressionDef_VC3_1"; - if ( aafUIDCmp( auid, &AAFCompressionDef_Avid_DNxHD_Legacy ) ) return L"AAFCompressionDef_Avid_DNxHD_Legacy"; - - return L"Unknown AAFCompressionDef"; + return "n/a"; + + if ( aafUIDCmp( auid, &AUID_NULL ) ) return "AUID_NULL"; + if ( aafUIDCmp( auid, &AAFCompressionDef_AAF_CMPR_FULL_JPEG ) ) return "AAFCompressionDef_AAF_CMPR_FULL_JPEG"; + if ( aafUIDCmp( auid, &AAFCompressionDef_AAF_CMPR_AUNC422 ) ) return "AAFCompressionDef_AAF_CMPR_AUNC422"; + if ( aafUIDCmp( auid, &AAFCompressionDef_LegacyDV ) ) return "AAFCompressionDef_LegacyDV"; + if ( aafUIDCmp( auid, &AAFCompressionDef_SMPTE_D10_50Mbps_625x50I ) ) return "AAFCompressionDef_SMPTE_D10_50Mbps_625x50I"; + if ( aafUIDCmp( auid, &AAFCompressionDef_SMPTE_D10_50Mbps_525x5994I ) ) return "AAFCompressionDef_SMPTE_D10_50Mbps_525x5994I"; + if ( aafUIDCmp( auid, &AAFCompressionDef_SMPTE_D10_40Mbps_625x50I ) ) return "AAFCompressionDef_SMPTE_D10_40Mbps_625x50I"; + if ( aafUIDCmp( auid, &AAFCompressionDef_SMPTE_D10_40Mbps_525x5994I ) ) return "AAFCompressionDef_SMPTE_D10_40Mbps_525x5994I"; + if ( aafUIDCmp( auid, &AAFCompressionDef_SMPTE_D10_30Mbps_625x50I ) ) return "AAFCompressionDef_SMPTE_D10_30Mbps_625x50I"; + if ( aafUIDCmp( auid, &AAFCompressionDef_SMPTE_D10_30Mbps_525x5994I ) ) return "AAFCompressionDef_SMPTE_D10_30Mbps_525x5994I"; + if ( aafUIDCmp( auid, &AAFCompressionDef_IEC_DV_525_60 ) ) return "AAFCompressionDef_IEC_DV_525_60"; + if ( aafUIDCmp( auid, &AAFCompressionDef_IEC_DV_625_50 ) ) return "AAFCompressionDef_IEC_DV_625_50"; + if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_25Mbps_525_60 ) ) return "AAFCompressionDef_DV_Based_25Mbps_525_60"; + if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_25Mbps_625_50 ) ) return "AAFCompressionDef_DV_Based_25Mbps_625_50"; + if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_50Mbps_525_60 ) ) return "AAFCompressionDef_DV_Based_50Mbps_525_60"; + if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_50Mbps_625_50 ) ) return "AAFCompressionDef_DV_Based_50Mbps_625_50"; + if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_100Mbps_1080x5994I ) ) return "AAFCompressionDef_DV_Based_100Mbps_1080x5994I"; + if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_100Mbps_1080x50I ) ) return "AAFCompressionDef_DV_Based_100Mbps_1080x50I"; + if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_100Mbps_720x5994P ) ) return "AAFCompressionDef_DV_Based_100Mbps_720x5994P"; + if ( aafUIDCmp( auid, &AAFCompressionDef_DV_Based_100Mbps_720x50P ) ) return "AAFCompressionDef_DV_Based_100Mbps_720x50P"; + if ( aafUIDCmp( auid, &AAFCompressionDef_VC3_1 ) ) return "AAFCompressionDef_VC3_1"; + if ( aafUIDCmp( auid, &AAFCompressionDef_Avid_DNxHD_Legacy ) ) return "AAFCompressionDef_Avid_DNxHD_Legacy"; + + return "Unknown AAFCompressionDef"; } diff --git a/src/AAFIface/AAFIAudioFiles.c b/src/AAFIface/AAFIAudioFiles.c deleted file mode 100644 index 231beb1..0000000 --- a/src/AAFIface/AAFIAudioFiles.c +++ /dev/null @@ -1,700 +0,0 @@ -/* - * Copyright (C) 2017-2023 Adrien Gesta-Fline - * - * This file is part of libAAF. - * - * 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 "RIFFParser.h" -#include "URIParser.h" - -#include - -#if defined(__linux__) - #include - #include - #include - #include /* access() */ -#elif defined(__APPLE__) - #include - #include /* access() */ -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) - #include - #define R_OK 4 /* Test for read permission. */ - #define W_OK 2 /* Test for write permission. */ - #define F_OK 0 /* Test for existence. */ - #ifndef _MSC_VER - #include // access() - #endif -#endif - - - -#define WAV_FILE_EXT "wav" -#define AIFF_FILE_EXT "aif" - - -#define debug( ... ) \ - _dbg( aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) - -#define warning( ... ) \ - _dbg( aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) - -#define error( ... ) \ - _dbg( aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) - - - - - -static size_t embeddedAudioDataReaderCallback( unsigned char *buf, size_t offset, size_t reqLen, void *user1, void *user2, void *user3 ); -static size_t externalAudioDataReaderCallback( unsigned char *buf, size_t offset, size_t reqLen, void *user1, void *user2, void *user3 ); - - - - -wchar_t * aafi_locate_external_essence_file( AAF_Iface *aafi, const wchar_t *original_uri_filepath, const char *search_location ) -{ - /* - * Absolute Uniform Resource Locator (URL) complying with RFC 1738 or relative - * Uniform Resource Identifier (URI) complying with RFC 2396 for file containing - * the essence. If it is a relative URI, the base URI is determined from the URI - * of the AAF file itself. - * - * Informative note: A valid URL or URI uses a constrained character set and - * uses the / character as the path separator. - */ - - char *uri_filepath = NULL; - char *local_filepath = NULL; - char *aaf_path = NULL; - char *foundpath = NULL; - wchar_t *retpath = NULL; - - struct uri *uri = NULL; - - if ( original_uri_filepath == NULL ) { - error( "Cant locate a NULL filepath" ); - goto err; - } - - - uri_filepath = laaf_util_wstr2str( original_uri_filepath ); - - if ( uri_filepath == NULL ) { - error( "Could not convert original_uri_filepath from wstr to str : %ls", original_uri_filepath ); - goto err; - } - - // debug( "Original URI : %s", uri_filepath ); - - - uri = uriParse( uri_filepath, URI_OPT_DECODE_ALL, aafi->dbg ); - - if ( uri == NULL ) { - error( "Could not parse URI" ); - goto err; - } - - if ( uri->path == NULL ) { - error( "Could not retrieve out of URI" ); - goto err; - } - - // debug( "Decoded URI's path : %s", uri->path ); - - - - /* extract relative path to essence file : "/" */ - - char *relativeEssencePath = NULL; - char *p = uri->path + strlen(uri->path); - - int sepcount = 0; - - while ( p > uri->path ) { - if ( *p == '/' ) { /* parsing URI, so will always be '/' as separator character */ - sepcount++; - if ( sepcount == 2 ) { - relativeEssencePath = (p+1); - break; - } - } - p--; - } - - - const char *essenceFileName = laaf_util_fop_get_file( uri->path ); - - // debug( "Essence filename : %s", essenceFileName ); - - - if ( search_location ) { - - /* - * "/" - */ - - local_filepath = laaf_util_build_path( DIR_SEP_STR, search_location, essenceFileName, NULL ); - - if ( local_filepath == NULL ) { - error( "Could not build search filepath" ); - goto err; - } - - // debug( "Search filepath : %s", local_filepath ); - - if ( access( local_filepath, F_OK ) != -1 ) { - // debug( "FOUND: %s", local_filepath ); - foundpath = local_filepath; - goto found; - } - - free( local_filepath ); local_filepath = NULL; - - - /* - * "//" - */ - - local_filepath = laaf_util_build_path( DIR_SEP_STR, search_location, relativeEssencePath, NULL ); - - if ( local_filepath == NULL ) { - error( "Could not build search filepath" ); - goto err; - } - - // debug( "Search filepath : %s", local_filepath ); - - if ( access( local_filepath, F_OK ) != -1 ) { - // debug( "FOUND: %s", local_filepath ); - foundpath = local_filepath; - goto found; - } - - free( local_filepath ); local_filepath = NULL; - } - - - /* Try AAF essence's URI */ - - if ( access( uri_filepath, F_OK ) != -1 ) { - // debug( "FOUND: %s", uri_filepath ); - foundpath = uri_filepath; - goto found; - } - - - /* Try part of URI */ - - if ( access( uri->path, F_OK ) != -1 ) { - // debug( "FOUND: %s", uri->path ); - foundpath = uri->path; - goto found; - } - - - if ( uri->flags & URI_T_LOCALHOST ) { - // debug( "URI targets localhost : %s", uri_filepath ); - } - else { - if ( uri->flags & URI_T_HOST_IPV4 ) { - // debug( "URI targets IPV4 : %s", uri_filepath ); - } - else if ( uri->flags & URI_T_HOST_IPV6 ) { - // debug( "URI targets IPV6 : %s", uri_filepath ); - } - else if ( uri->flags & URI_T_HOST_REGNAME ) { - // debug( "URI targets hostname : %s", uri_filepath ); - } - } - - - /* - * Try to locate essence file from the AAF file location. - * - * e.g. - * - AAF filepath : /home/user/AAFFile.aaf - * - Essence URI : file://localhost/C:/Users/user/Desktop/AudioFiles/essence.wav - * = /home/user/AudioFiles/essence.file - */ - - - /* extract path to AAF file */ - - aaf_path = laaf_util_c99strdup( aafi->aafd->cfbd->file ); - - if ( aaf_path == NULL ) { - error( "Could not duplicate AAF filepath" ); - goto err; - } - - p = aaf_path + strlen(aaf_path); - - while ( p > aaf_path ) { - if ( IS_DIR_SEP(*p) ) { - *p = 0x00; - break; - } - p--; - } - - - /* - * "/" - */ - - local_filepath = laaf_util_build_path( DIR_SEP_STR, aaf_path, essenceFileName, NULL ); - - if ( local_filepath == NULL ) { - error( "Could not build filepath" ); - goto err; - } - - // debug( "AAF relative filepath : %s", local_filepath ); - - if ( access( local_filepath, F_OK ) != -1 ) { - // debug( "FOUND: %s", filepath ); - foundpath = local_filepath; - goto found; - } - - free( local_filepath ); local_filepath = NULL; - - - /* - * "//" - */ - - local_filepath = laaf_util_build_path( DIR_SEP_STR, aaf_path, relativeEssencePath, NULL ); - - if ( local_filepath == NULL ) { - error( "Could not build filepath" ); - goto err; - } - - // debug( "AAF relative filepath : %s", local_filepath ); - - if ( access( local_filepath, F_OK ) != -1 ) { - // debug( "FOUND: %s", filepath ); - foundpath = local_filepath; - goto found; - } - - free( local_filepath ); local_filepath = NULL; - - - // debug("File not found"); - -found: - if ( foundpath ) { - retpath = laaf_util_str2wstr( foundpath ); - - if ( retpath == NULL ) { - error( "Could not convert foundpath from str to wstr : %s", foundpath ); - goto err; - } - } - - goto end; - -err: - retpath = NULL; - -end: - if ( uri ) - uriFree( uri ); - - if ( uri_filepath ) - free( uri_filepath ); - - if ( local_filepath ) - free( local_filepath ); - - if ( aaf_path ) - free( aaf_path ); - - return retpath; - - - /* - * AAFInfo --aaf-clips ../libaaf_testfiles/fonk_2.AAF - file://localhost/Users/horlaprod/Music/Logic/fonk_2/Audio Files_1/fonk_2_3#04.wav - - * AAFInfo --aaf-clips ../libaaf_testfiles/ADP/ADP3_51-ST-MONO-NOBREAKOUT.aaf - file:///C:/Users/Loviniou/Downloads/ChID-BLITS-EBU-Narration441-16b.wav - - * AAFInfo --aaf-clips ../libaaf_testfiles/ADP/ADP2_SEQ-FULL.aaf - file://?/E:/Adrien/ADPAAF/Sequence A Rendu.mxf - - * AAFInfo --aaf-clips ../libaaf_testfiles/TEST-AVID_COMP2977052\ \ -\ \ OFF\ PODIUM\ ETAPE\ 2.aaf - file:////C:/Users/mix_limo/Desktop/TEST2977052 - OFF PODIUM ETAPE 2.aaf - - * AAFInfo --aaf-clips ../ardio/watchfolder/3572607_RUGBY_F_1_1.aaf - file://10.87.230.71/mixage/DR2/Avid MediaFiles/MXF/1/3572607_RUGBY_F2_S65CFA3D0V.mxf - - * AAFInfo --aaf-clips ../libaaf_testfiles/ProTools/pt2MCC.aaf - file:///_system/Users/horlaprod/pt2MCCzmhsFRHQgdgsTMQX.mxf - */ -} - - - -int aafi_extract_audio_essence( AAF_Iface *aafi, aafiAudioEssence *audioEssence, const char *outfilepath, const wchar_t *forcedFileName ) -{ - int rc = 0; - int reqlen = 0; - FILE *fp = NULL; - char *filename = NULL; - char *filepath = NULL; - - unsigned char *data = NULL; - uint64_t datasz = 0; - - - if ( audioEssence->is_embedded == 0 ) { - warning( "Audio essence is not embedded : nothing to extract" ); - return -1; - } - - - /* Retrieve stream from CFB */ - - cfb_getStream( aafi->aafd->cfbd, audioEssence->node, &data, &datasz ); - - if ( data == NULL ) { - error( "Could not retrieve audio essence stream from CFB" ); - goto err; - } - - - /* Build file path */ - - reqlen = snprintf( NULL, 0, "%ls.%s", ( forcedFileName != NULL ) ? forcedFileName : audioEssence->unique_file_name, (audioEssence->type == AAFI_ESSENCE_TYPE_AIFC) ? AIFF_FILE_EXT : WAV_FILE_EXT ); - - if ( reqlen < 0 ) { - error( "Failed to build filename" ); - goto err; - } - - int filenamelen = reqlen+1; - - - filename = malloc( filenamelen ); - - if ( filename == NULL ) { - error( "Could not allocate memory : %s", strerror(errno) ); - goto err; - } - - - rc = snprintf( filename, filenamelen, "%ls.%s", ( forcedFileName != NULL ) ? forcedFileName : audioEssence->unique_file_name, (audioEssence->type == AAFI_ESSENCE_TYPE_AIFC) ? AIFF_FILE_EXT : WAV_FILE_EXT ); - - if ( rc < 0 || (unsigned)rc >= (unsigned)filenamelen ) { - error( "Failed to build filename" ); - goto err; - } - - - filepath = laaf_util_build_path( DIR_SEP_STR, outfilepath, laaf_util_clean_filename(filename), NULL ); - - if ( filepath == NULL ) { - error( "Could not build filepath" ); - goto err; - } - - - fp = fopen( filepath, "wb" ); - - if ( fp == NULL ) { - error( "Could not open '%s' for writing : %s", filepath, strerror(errno) ); - goto err; - } - - - if ( audioEssence->type == AAFI_ESSENCE_TYPE_PCM ) { - - struct wavFmtChunk wavFmt; - wavFmt.channels = audioEssence->channels; - wavFmt.samples_per_sec = audioEssence->samplerate; - wavFmt.bits_per_sample = audioEssence->samplesize; - - struct wavBextChunk wavBext; - memset( &wavBext, 0x00, sizeof(wavBext) ); - memcpy( wavBext.umid, audioEssence->sourceMobID, sizeof(aafMobID_t) ); - if ( audioEssence->mobSlotEditRate ) { - wavBext.time_reference = laaf_util_converUnit( audioEssence->timeReference, audioEssence->mobSlotEditRate, audioEssence->samplerateRational ); - } - - if ( datasz >= (uint32_t)-1 ) { - // TODO RF64 support ? - error( "Audio essence is bigger than maximum wav file size (2^32 bytes) : %"PRIu64" bytes", datasz ); - goto err; - } - - if ( riff_writeWavFileHeader( fp, &wavFmt, &wavBext, (uint32_t)datasz, aafi->dbg ) < 0 ) { - error( "Could not write wav audio header : %s", filepath ); - goto err; - } - } - - - uint64_t writtenBytes = fwrite( data, sizeof(unsigned char), datasz, fp ); - - if ( writtenBytes < datasz ) { - error( "Could not write audio file (%"PRIu64" bytes written out of %"PRIu64" bytes) : %s", writtenBytes, datasz, filepath ); - goto err; - } - - - audioEssence->usable_file_path = malloc( (strlen(filepath) + 1) * sizeof(wchar_t) ); - - if ( audioEssence->usable_file_path == NULL ) { - error( "Could not allocate memory : %s", strerror(errno) ); - goto err; - } - - - audioEssence->usable_file_path = laaf_util_str2wstr( filepath ); - - if ( audioEssence->usable_file_path == NULL ) { - error( "Could not convert usable_file_path from str to wstr : %s", filepath ); - goto err; - } - - rc = 0; - goto end; - -err: - rc = -1; - -end: - if ( filename ) - free( filename ); - - if ( filepath ) - free( filepath ); - - if ( data ) - free( data ); - - if ( fp ) - fclose( fp ); - - return rc; -} - - - -int aafi_parse_audio_essence( AAF_Iface *aafi, aafiAudioEssence *audioEssence ) -{ - // aafi->dbg->_dbg_msg_pos += laaf_util_dump_hex( audioEssence->summary->val, audioEssence->summary->len, &aafi->dbg->_dbg_msg, &aafi->dbg->_dbg_msg_size, aafi->dbg->_dbg_msg_pos ); - - int rc = 0; - char *externalFilePath = NULL; - FILE *fp = NULL; - struct RIFFAudioFile RIFFAudioFile; - - - /* try audioEssence->summary first, for both embedded and external */ - - if ( audioEssence->summary ) { - - rc = riff_parseAudioFile( &RIFFAudioFile, RIFF_PARSE_AAF_SUMMARY, &embeddedAudioDataReaderCallback, audioEssence->summary->val, &audioEssence->summary->len, aafi, aafi->dbg ); - - if ( rc < 0 ) { - - warning( "Could not parse essence summary of %ls", audioEssence->file_name ); - - if ( audioEssence->is_embedded ) { - return -1; - } - } - else { - audioEssence->channels = RIFFAudioFile.channels; - audioEssence->samplerate = RIFFAudioFile.sampleRate; - audioEssence->samplesize = RIFFAudioFile.sampleSize; - audioEssence->length = RIFFAudioFile.sampleCount; - - audioEssence->samplerateRational->numerator = audioEssence->samplerate; - audioEssence->samplerateRational->denominator = 1; - - return 0; - } - } - else if ( audioEssence->is_embedded ) { - - if ( audioEssence->type != AAFI_ESSENCE_TYPE_PCM ) { - warning( "TODO: Embedded audio essence has no summary. Should we try essence data stream ?" ); - } - - return -1; - } - else if ( !audioEssence->usable_file_path ) { - // warning( "Can't parse a missing external essence file" ); - return -1; - } - - - if ( laaf_util_fop_is_wstr_fileext( audioEssence->usable_file_path, L"wav" ) || - laaf_util_fop_is_wstr_fileext( audioEssence->usable_file_path, L"wave" ) || - laaf_util_fop_is_wstr_fileext( audioEssence->usable_file_path, L"aif" ) || - laaf_util_fop_is_wstr_fileext( audioEssence->usable_file_path, L"aiff" ) || - laaf_util_fop_is_wstr_fileext( audioEssence->usable_file_path, L"aifc" ) ) - { - externalFilePath = laaf_util_wstr2str( audioEssence->usable_file_path ); - - if ( externalFilePath == NULL ) { - error( "Could not convert usable_file_path from wstr to str : %ls", audioEssence->usable_file_path ); - goto err; - } - - - fp = fopen( externalFilePath, "rb" ); - - if ( fp == NULL ) { - error( "Could not open external audio essence file for reading : %s", externalFilePath ); - goto err; - } - - - rc = riff_parseAudioFile( &RIFFAudioFile, 0, &externalAudioDataReaderCallback, fp, externalFilePath, aafi, aafi->dbg ); - - if ( rc < 0 ) { - error( "Failed parsing external audio essence file : %s", externalFilePath ); - goto err; - } - - - if ( audioEssence->channels > 0 && audioEssence->channels != RIFFAudioFile.channels ) { - warning( "%ls : summary channel count (%i) mismatch located file (%i)", audioEssence->usable_file_path, audioEssence->channels, RIFFAudioFile.channels ); - } - - if ( audioEssence->samplerate > 0 && audioEssence->samplerate != RIFFAudioFile.sampleRate ) { - warning( "%ls : summary samplerate (%i) mismatch located file (%i)", audioEssence->usable_file_path, audioEssence->samplerate, RIFFAudioFile.sampleRate ); - } - - if ( audioEssence->samplesize > 0 && audioEssence->samplesize != RIFFAudioFile.sampleSize ) { - warning( "%ls : summary samplesize (%i) mismatch located file (%i)", audioEssence->usable_file_path, audioEssence->samplesize, RIFFAudioFile.sampleSize ); - } - - if ( audioEssence->length > 0 && audioEssence->length != RIFFAudioFile.sampleCount ) { - warning( "%ls : summary samplecount (%"PRIi64") mismatch located file (%"PRIi64")", audioEssence->usable_file_path, audioEssence->length, RIFFAudioFile.sampleCount ); - } - - audioEssence->channels = RIFFAudioFile.channels; - audioEssence->samplerate = RIFFAudioFile.sampleRate; - audioEssence->samplesize = RIFFAudioFile.sampleSize; - audioEssence->length = RIFFAudioFile.sampleCount; - - audioEssence->samplerateRational->numerator = audioEssence->samplerate; - audioEssence->samplerateRational->denominator = 1; - } - else { - /* - * should be considered as a non-pcm audio format - * -│ 04317│├──◻ AAFClassID_TimelineMobSlot [slot:6 track:4] (DataDef : AAFDataDef_Sound) : Audio 4 - Layered Audio Editing -│ 01943││ └──◻ AAFClassID_Sequence -│ 02894││ └──◻ AAFClassID_SourceClip -│ 02899││ └──◻ AAFClassID_MasterMob (UsageCode: n/a) : speech-sample -│ 04405││ └──◻ AAFClassID_TimelineMobSlot [slot:1 track:1] (DataDef : AAFDataDef_Sound) -│ 03104││ └──◻ AAFClassID_SourceClip -│ 04140││ └──◻ AAFClassID_SourceMob (UsageCode: n/a) : speech-sample -│ 01287││ └──◻ AAFClassID_PCMDescriptor -│ 01477││ └──◻ AAFClassID_NetworkLocator : file:///C:/Users/user/Desktop/libAAF/test/res/speech-sample.mp3 - * - */ - - audioEssence->type = AAFI_ESSENCE_TYPE_UNK; - - // /* clears any wrong data previously retrieved out of AAFClassID_PCMDescriptor */ - // audioEssence->samplerate = 0; - // audioEssence->samplesize = 0; - } - - - rc = 0; - goto end; - -err: - rc = -1; - -end: - if ( fp ) - fclose( fp ); - - if ( externalFilePath ) - free( externalFilePath ); - - return rc; -} - - - -static size_t embeddedAudioDataReaderCallback( unsigned char *buf, size_t offset, size_t reqLen, void *user1, void *user2, void *user3 ) -{ - unsigned char *data = user1; - size_t datasz = *(size_t*)user2; - AAF_Iface *aafi = (AAF_Iface*)user3; - - if ( offset > datasz ) { - error( "Requested data starts beyond data length" ); - return -1; - } - - if ( offset+reqLen > datasz ) { - reqLen = datasz - (offset+reqLen); - } - - memcpy( buf, data+offset, reqLen ); - - return reqLen; -} - - - -static size_t externalAudioDataReaderCallback( unsigned char *buf, size_t offset, size_t reqLen, void *user1, void *user2, void *user3 ) -{ - FILE *fp = (FILE*)user1; - const char *filename = (const char*)user2; - AAF_Iface *aafi = (AAF_Iface*)user3; - - if ( fseek( fp, offset, SEEK_SET ) < 0 ) { - error( "Could not seek to %zu in file '%s' : %s", offset, filename, strerror(errno) ); - return -1; - } - - size_t read = fread( buf, sizeof(unsigned char), reqLen, fp ); - - if ( read < reqLen ) { - error( "File read failed at %zu (expected %zu, read %zu) in file '%s' : %s", offset, reqLen, read, filename, strerror(errno) ); - return -1; - } - - return read; -} diff --git a/src/AAFIface/AAFIEssenceFile.c b/src/AAFIface/AAFIEssenceFile.c new file mode 100644 index 0000000..631cfa5 --- /dev/null +++ b/src/AAFIface/AAFIEssenceFile.c @@ -0,0 +1,1013 @@ +/* + * Copyright (C) 2017-2024 Adrien Gesta-Fline + * + * This file is part of libAAF. + * + * 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 + +#include "RIFFParser.h" +#include "URIParser.h" + + +#define debug( ... ) \ + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) + +#define success( ... ) \ + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_SUCCESS, __VA_ARGS__ ) + +#define warning( ... ) \ + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) + +#define error( ... ) \ + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) + + + +static int set_audioEssenceWithRIFF( AAF_Iface *aafi, const char *filename, aafiAudioEssenceFile *audioEssenceFile, struct RIFFAudioFile *RIFFAudioFile, int isExternalFile ); +static size_t embeddedAudioDataReaderCallback( unsigned char *buf, size_t offset, size_t reqLen, void *user1, void *user2, void *user3 ); +static size_t externalAudioDataReaderCallback( unsigned char *buf, size_t offset, size_t reqLen, void *user1, void *user2, void *user3 ); + + + +int aafi_build_unique_audio_essence_name( AAF_Iface *aafi, aafiAudioEssenceFile *audioEssenceFile ) +{ + if ( audioEssenceFile->unique_name ) { + debug( "Unique name was already set" ); + return -1; + } + + if ( aafi->ctx.options.mobid_essence_filename ) { + + aafUID_t *uuid = &(audioEssenceFile->sourceMobID->material); + + int rc = laaf_util_snprintf_realloc( &audioEssenceFile->unique_name, 0, 0, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", + uuid->Data1, + uuid->Data2, + uuid->Data3, + uuid->Data4[0], + uuid->Data4[1], + uuid->Data4[2], + uuid->Data4[3], + uuid->Data4[4], + uuid->Data4[5], + uuid->Data4[6], + uuid->Data4[7] ); + + if ( rc < 0 ) { + error( "Failed to set unique filename with SourceMobID UID" ); + free( audioEssenceFile->unique_name ); + return -1; + } + + return 0; + } + else { + audioEssenceFile->unique_name = laaf_util_c99strdup( (audioEssenceFile->name) ? audioEssenceFile->name : "unknown" ); + + if ( !audioEssenceFile->unique_name ) { + error( "Could not duplicate essence name : %s", (audioEssenceFile->name) ? audioEssenceFile->name : "unknown" ); + return -1; + } + } + + size_t unique_size = strlen( audioEssenceFile->unique_name ) + 1; + + int index = 0; + aafiAudioEssenceFile *ae = NULL; + + AAFI_foreachAudioEssenceFile( aafi, ae ) { + + if ( ae != audioEssenceFile && ae->unique_name != NULL && strcmp( ae->unique_name, audioEssenceFile->unique_name ) == 0 ) { + + if ( laaf_util_snprintf_realloc( &audioEssenceFile->unique_name, &unique_size, 0, "%s_%i", (audioEssenceFile->name) ? audioEssenceFile->name : "unknown", ++index ) < 0 ) { + error( "Failed to increment unique filename" ); + return -1; + } + + /* recheck entire essence list */ + ae = aafi->Audio->essenceFiles; + } + } + + return 0; +} + + + +char * aafi_locate_external_essence_file( AAF_Iface *aafi, const char *original_uri_filepath, const char *search_location ) +{ + /* + * Absolute Uniform Resource Locator (URL) complying with RFC 1738 or relative + * Uniform Resource Identifier (URI) complying with RFC 2396 for file containing + * the essence. If it is a relative URI, the base URI is determined from the URI + * of the AAF file itself. + * + * Informative note: A valid URL or URI uses a constrained character set and + * uses the / character as the path separator. + */ + + char *local_filepath = NULL; + char *aaf_path = NULL; + const char *foundpath = NULL; + char *retpath = NULL; + + struct uri *uri = NULL; + + if ( original_uri_filepath == NULL ) { + error( "Cant locate a NULL filepath" ); + goto err; + } + + debug( "Original URI : %s", original_uri_filepath ); + + + uri = laaf_uri_parse( original_uri_filepath, URI_OPT_DECODE_ALL, aafi->log ); + + if ( uri == NULL ) { + error( "Could not parse URI" ); + goto err; + } + + if ( uri->path == NULL ) { + error( "Could not retrieve out of URI" ); + goto err; + } + + debug( "Decoded URI's path : %s", uri->path ); + + + /* extract relative path to essence file : "/" */ + + const char *relativeEssencePath = NULL; + const char *essenceFileName = NULL; + + int sepcount = 0; + char *p = uri->path + strlen(uri->path); + + while ( p > uri->path ) { + if ( *p == '/' ) { /* parsing URI, so will always be '/' as separator character */ + sepcount++; + if ( sepcount == 1 ) { + essenceFileName = (p+1); + } + else + if ( sepcount == 2 ) { + relativeEssencePath = (p+1); + break; + } + } + p--; + } + + if ( !relativeEssencePath ) { + error( "Could not retrieve relative file path out of URI : %s", uri->path ); + goto err; + } + + if ( !essenceFileName ) { + error( "Could not retrieve file name out of URI : %s", uri->path ); + goto err; + } + + debug( "Essence filename : %s", essenceFileName ); + + + if ( search_location ) { + + /* + * "/" + */ + + local_filepath = laaf_util_build_path( "/", search_location, essenceFileName, NULL ); + + if ( !local_filepath ) { + error( "Could not build search filepath" ); + goto err; + } + + debug( "Search filepath : %s", local_filepath ); + + + if ( laaf_util_file_exists( local_filepath ) == 1 ) { + foundpath = local_filepath; + goto found; + } + + free( local_filepath ); local_filepath = NULL; + + + /* + * "//" + */ + + local_filepath = laaf_util_build_path( "/", search_location, relativeEssencePath, NULL ); + + if ( !local_filepath ) { + error( "Could not build search filepath" ); + goto err; + } + + debug( "Search filepath : %s", local_filepath ); + + if ( laaf_util_file_exists( local_filepath ) == 1 ) { + foundpath = local_filepath; + goto found; + } + + free( local_filepath ); local_filepath = NULL; + } + + + /* Try AAF essence's URI */ + + if ( laaf_util_file_exists( original_uri_filepath ) == 1 ) { + foundpath = original_uri_filepath; + goto found; + } + + + /* Try part of URI */ + + if ( laaf_util_file_exists( uri->path ) == 1 ) { + foundpath = uri->path; + goto found; + } + + + if ( uri->flags & URI_T_LOCALHOST ) { + // debug( "URI targets localhost : %s", uri_filepath ); + } + else { + if ( uri->flags & URI_T_HOST_IPV4 ) { + // debug( "URI targets IPV4 : %s", uri_filepath ); + } + else if ( uri->flags & URI_T_HOST_IPV6 ) { + // debug( "URI targets IPV6 : %s", uri_filepath ); + } + else if ( uri->flags & URI_T_HOST_REGNAME ) { + // debug( "URI targets hostname : %s", uri_filepath ); + } + } + + + /* + * Try to locate essence file from the AAF file location. + * + * e.g. + * - AAF filepath : /home/user/AAFFile.aaf + * - Essence URI : file://localhost/C:/Users/user/Desktop/AudioFiles/essence.wav + * = /home/user/AudioFiles/essence.file + */ + + + /* extract path to AAF file */ + + aaf_path = laaf_util_c99strdup( aafi->aafd->cfbd->file ); + + if ( !aaf_path ) { + error( "Could not duplicate AAF filepath : %s", aafi->aafd->cfbd->file ); + goto err; + } + + p = aaf_path + strlen(aaf_path); + + while ( p > aaf_path ) { + if ( IS_DIR_SEP(*p) ) { + *p = 0x00; + break; + } + p--; + } + + + /* + * "/" + */ + + local_filepath = laaf_util_build_path( DIR_SEP_STR, aaf_path, essenceFileName, NULL ); + + if ( !local_filepath ) { + error( "Could not build filepath" ); + goto err; + } + + debug( "AAF relative filepath : %s", local_filepath ); + + if ( laaf_util_file_exists( local_filepath ) == 1 ) { + foundpath = local_filepath; + goto found; + } + + free( local_filepath ); local_filepath = NULL; + + + /* + * "//" + */ + + local_filepath = laaf_util_build_path( DIR_SEP_STR, aaf_path, relativeEssencePath, NULL ); + + if ( !local_filepath ) { + error( "Could not build filepath" ); + goto err; + } + + debug( "AAF relative sub filepath : %s", local_filepath ); + + if ( laaf_util_file_exists( local_filepath ) == 1 ) { + foundpath = local_filepath; + goto found; + } + + free( local_filepath ); local_filepath = NULL; + + + debug( "File not found" ); + +found: + if ( foundpath ) { + /* + * When runing through wine, computing absolute path adds a Z:/ drive letter. + * This causes issue when trying to make relative essence path from the AAF + * file path, since it also went through laaf_util_absolute_path(). + * So even if foundpath is already absolute, we need that drive letter at it + * start. + */ + // retpath = laaf_util_c99strdup(foundpath); + retpath = laaf_util_absolute_path(foundpath); + + if ( !retpath ) { + error( "Could not make absolute path to located file : %s", foundpath ); + goto err; + } + + debug( "File found at : %s", foundpath ); + } + + goto end; + +err: + retpath = NULL; + +end: + laaf_uri_free( uri ); + + free( local_filepath ); + free( aaf_path ); + + return retpath; + + + /* + * AAFInfo --aaf-clips ../libaaf_testfiles/fonk_2.AAF + file://localhost/Users/horlaprod/Music/Logic/fonk_2/Audio Files_1/fonk_2_3#04.wav + + * AAFInfo --aaf-clips ../libaaf_testfiles/ADP/ADP3_51-ST-MONO-NOBREAKOUT.aaf + file:///C:/Users/Loviniou/Downloads/ChID-BLITS-EBU-Narration441-16b.wav + + * AAFInfo --aaf-clips ../libaaf_testfiles/ADP/ADP2_SEQ-FULL.aaf + file://?/E:/Adrien/ADPAAF/Sequence A Rendu.mxf + + * AAFInfo --aaf-clips ../libaaf_testfiles/TEST-AVID_COMP2977052\ \ -\ \ OFF\ PODIUM\ ETAPE\ 2.aaf + file:////C:/Users/mix_limo/Desktop/TEST2977052 - OFF PODIUM ETAPE 2.aaf + + * AAFInfo --aaf-clips ../ardio/watchfolder/3572607_RUGBY_F_1_1.aaf + file://10.87.230.71/mixage/DR2/Avid MediaFiles/MXF/1/3572607_RUGBY_F2_S65CFA3D0V.mxf + + * AAFInfo --aaf-clips ../libaaf_testfiles/ProTools/pt2MCC.aaf + file:///_system/Users/horlaprod/pt2MCCzmhsFRHQgdgsTMQX.mxf + */ +} + + + +int aafi_extractAudioEssenceFile( AAF_Iface *aafi, aafiAudioEssenceFile *audioEssenceFile, enum aafiExtractFormat extractFormat, const char *outpath, uint64_t sampleOffset, uint64_t sampleLength, const char *forcedFileName, char **usable_file_path ) +{ + int rc = 0; + int tmp = 0; + FILE *fp = NULL; + char *filename = NULL; + char *filepath = NULL; + + int write_header = 0; + int extracting_clip = 0; + + unsigned char *data = NULL; + uint64_t datasz = 0; + + + if ( audioEssenceFile->is_embedded == 0 ) { + error( "Audio essence is not embedded : nothing to extract" ); + goto err; + } + + if ( !outpath ) { + error( "Missing output path" ); + goto err; + } + + if ( audioEssenceFile->usable_file_path ) { + debug( "usable_file_path was already set" ); + free( audioEssenceFile->usable_file_path ); + audioEssenceFile->usable_file_path = NULL; + } + + uint64_t pcmByteOffset = sampleOffset * audioEssenceFile->channels * (audioEssenceFile->samplesize/8); + uint64_t pcmByteLength = sampleLength * audioEssenceFile->channels * (audioEssenceFile->samplesize/8); + + + /* Retrieve stream from CFB */ + + cfb_getStream( aafi->aafd->cfbd, audioEssenceFile->node, &data, &datasz ); + + if ( data == NULL ) { + error( "Could not retrieve audio essence stream from CFB" ); + goto err; + } + + + /* Calculate offset and length */ + + debug( "Requesting extract of essence \"%s\"", audioEssenceFile->name ); + debug( " - ReqSampleOffset: %"PRIu64" samples (%"PRIu64" bytes)", sampleOffset, pcmByteOffset ); + debug( " - ReqSampleLength: %"PRIu64" samples (%"PRIu64" bytes)", sampleLength, pcmByteLength ); + debug( " - FileHeaderOffset: %"PRIu64" bytes (0x%04"PRIx64")", + audioEssenceFile->pcm_audio_start_offset, + audioEssenceFile->pcm_audio_start_offset ); + debug( " - EssenceTotalLength: %"PRIu64" bytes", datasz ); + + uint64_t sourceFileOffset = 0; + + if ( pcmByteOffset || + pcmByteLength || + extractFormat != AAFI_EXTRACT_DEFAULT ) + { + if ( audioEssenceFile->type != AAFI_ESSENCE_TYPE_PCM ) { + sourceFileOffset += audioEssenceFile->pcm_audio_start_offset; + } + write_header = 1; + } + + if ( pcmByteOffset || pcmByteLength ) { + extracting_clip = 1; + } + + sourceFileOffset += pcmByteOffset; + + + if ( (datasz - audioEssenceFile->pcm_audio_start_offset) < (pcmByteLength + sourceFileOffset) ) { + error( "Requested audio range (%"PRIi64" bytes) is bigger than source audio size (%"PRIu64" bytes)", + (pcmByteLength + sourceFileOffset), + datasz - audioEssenceFile->pcm_audio_start_offset ); + goto err; + } + + datasz = (pcmByteLength) ? pcmByteLength : (datasz-sourceFileOffset); + + if ( datasz >= (uint32_t)-1 ) { + error( "Audio essence is bigger than maximum wav file size (2^32 bytes) : %"PRIu64" bytes", datasz ); + goto err; + } + + debug( " - Calculated Offset: %"PRIu64" bytes", sourceFileOffset ); + debug( " - Calculated Length: %"PRIu64" bytes", datasz ); + + if ( audioEssenceFile->type != AAFI_ESSENCE_TYPE_PCM ) { + if ( !write_header ) { + debug( "Writting exact copy of embedded file." ); + } else { + debug( "Rewriting file header." ); + } + } + + + /* Build file path */ + const char *name = NULL; + + if ( forcedFileName ) { + name = forcedFileName; + } else { + name = audioEssenceFile->unique_name; + } + + const char *fileext = NULL; + + if ( write_header || + audioEssenceFile->type == AAFI_ESSENCE_TYPE_WAVE || + audioEssenceFile->type == AAFI_ESSENCE_TYPE_PCM ) + { + if ( !laaf_util_is_fileext( name, "wav" ) && + !laaf_util_is_fileext( name, "wave" ) ) + { + fileext = "wav"; + } + } + else if ( !write_header && + audioEssenceFile->type == AAFI_ESSENCE_TYPE_AIFC ) + { + if ( !laaf_util_is_fileext( name, "aif" ) && + !laaf_util_is_fileext( name, "aiff" ) && + !laaf_util_is_fileext( name, "aifc" ) ) + { + fileext = "aif"; + } + } + + + if ( fileext ) { + if ( laaf_util_snprintf_realloc( &filename, NULL, 0, "%s.%s", name, fileext ) < 0 ) { + error( "Could not concat filename + fileext" ); + goto err; + } + } + else { + filename = laaf_util_c99strdup( name ); + + if ( !filename ) { + error( "Could not duplicate filename : %s", name ); + goto err; + } + } + + + filepath = laaf_util_build_path( DIR_SEP_STR, outpath, laaf_util_clean_filename(filename), NULL ); + + if ( !filepath ) { + error( "Could not build filepath." ); + goto err; + } + + + fp = fopen( filepath, "wb" ); + + if ( !fp ) { + error( "Could not open '%s' for writing : %s", filepath, strerror(errno) ); + goto err; + } + + + if ( write_header || + audioEssenceFile->type == AAFI_ESSENCE_TYPE_PCM ) + { + struct wavFmtChunk wavFmt; + wavFmt.channels = audioEssenceFile->channels; + wavFmt.samples_per_sec = audioEssenceFile->samplerate; + wavFmt.bits_per_sample = audioEssenceFile->samplesize; + + struct wavBextChunk wavBext; + memset( &wavBext, 0x00, sizeof(wavBext) ); + + memcpy( wavBext.umid, audioEssenceFile->sourceMobID, sizeof(aafMobID_t) ); + + tmp = snprintf( wavBext.originator, sizeof(((struct wavBextChunk *)0)->originator), "%s %s", aafi->aafd->Identification.ProductName, (mediaComposer_AAF(aafi)) ? "" : aafi->aafd->Identification.ProductVersionString ); + + assert( tmp > 0 && (size_t)tmp < sizeof(((struct wavBextChunk *)0)->originator) ); + + // if ( tmp < 0 || (size_t)tmp >= sizeof(((struct wavBextChunk *)0)->originator) ) { + // fprintf( stderr, "snprintf() error" ); + // goto err; + // } + + tmp = snprintf( wavBext.originator_reference, sizeof(((struct wavBextChunk *)0)->originator_reference), "libAAF %s", LIBAAF_VERSION ); + + assert( tmp > 0 && (size_t)tmp < sizeof(((struct wavBextChunk *)0)->originator_reference) ); + + // if ( tmp < 0 || (size_t)tmp >= sizeof(((struct wavBextChunk *)0)->originator_reference) ) { + // fprintf( stderr, "snprintf() error" ); + // goto err; + // } + + tmp = snprintf( wavBext.description, sizeof(((struct wavBextChunk *)0)->description), "%s\n%s.aaf", audioEssenceFile->name, aafi->compositionName ); + + assert( tmp > 0 && (size_t)tmp < sizeof(((struct wavBextChunk *)0)->description) ); + + // if ( tmp < 0 || (size_t)tmp >= sizeof(((struct wavBextChunk *)0)->description) ) { + // fprintf( stderr, "snprintf() error" ); + // goto err; + // } + + memcpy( wavBext.origination_date, audioEssenceFile->originationDate, sizeof(((struct wavBextChunk *)0)->origination_date) ); + memcpy( wavBext.origination_time, audioEssenceFile->originationTime, sizeof(((struct wavBextChunk *)0)->origination_time) ); + + wavBext.time_reference = aafi_convertUnitUint64( audioEssenceFile->sourceMobSlotOrigin, audioEssenceFile->sourceMobSlotEditRate, audioEssenceFile->samplerateRational ); + + if ( laaf_riff_writeWavFileHeader( fp, &wavFmt, (extractFormat != AAFI_EXTRACT_WAV) ? &wavBext : NULL, (uint32_t)datasz, aafi->log ) < 0 ) { + error( "Could not write wav audio header : %s", filepath ); + goto err; + } + } + + + uint64_t writtenBytes = 0; + + if ( write_header && audioEssenceFile->type == AAFI_ESSENCE_TYPE_AIFC && audioEssenceFile->samplesize > 8 ) { + + unsigned char sample[4]; + uint16_t samplesize = (audioEssenceFile->samplesize>>3); + + for ( uint64_t i = 0; i < datasz; i += samplesize ) { + + if ( samplesize == 2 ) { + sample[0] = *(unsigned char*)(data+pcmByteOffset+i+1); + sample[1] = *(unsigned char*)(data+pcmByteOffset+i); + } + else if ( samplesize == 3 ) { + sample[0] = *(unsigned char*)(data+pcmByteOffset+i+2); + sample[1] = *(unsigned char*)(data+pcmByteOffset+i+1); + sample[2] = *(unsigned char*)(data+pcmByteOffset+i); + } + else if ( samplesize == 4 ) { + sample[0] = *(unsigned char*)(data+pcmByteOffset+i+3); + sample[1] = *(unsigned char*)(data+pcmByteOffset+i+2); + sample[2] = *(unsigned char*)(data+pcmByteOffset+i+1); + sample[3] = *(unsigned char*)(data+pcmByteOffset+i); + } + + writtenBytes += fwrite( sample, samplesize, 1, fp ); + } + + writtenBytes *= samplesize; + } + else { + writtenBytes = fwrite( data+sourceFileOffset, sizeof(unsigned char), datasz, fp ); + } + + if ( writtenBytes < datasz ) { + error( "Could not write audio file (%"PRIu64" bytes written out of %"PRIu64" bytes) : %s", writtenBytes, datasz, filepath ); + goto err; + } + + if ( !extracting_clip ) { + /* + * Set audioEssenceFile->usable_file_path only if we axtract essence, not if we + * extract clip (subset of an essence), as a single essence can have multiple + * clips using it. Otherwise, we would reset audioEssenceFile->usable_file_path + * as many times as there are clips using the same essence. + */ + audioEssenceFile->usable_file_path = laaf_util_c99strdup( filepath ); + + if ( !audioEssenceFile->usable_file_path ) { + error( "Could not duplicate usable filepath : %s", filepath ); + goto err; + } + } + + if ( usable_file_path ) { + *usable_file_path = laaf_util_c99strdup( filepath ); + + if ( !(*usable_file_path) ) { + error( "Could not duplicate usable filepath : %s", filepath ); + goto err; + } + } + + rc = 0; + goto end; + +err: + rc = -1; + +end: + free( filename ); + free( filepath ); + free( data ); + + if ( fp ) + fclose( fp ); + + return rc; +} + + + +int aafi_extractAudioClip( AAF_Iface *aafi, aafiAudioClip *audioClip, enum aafiExtractFormat extractFormat, const char *outpath ) +{ + int rc = 0; + + for ( aafiAudioEssencePointer *audioEssencePtr = audioClip->essencePointerList; audioEssencePtr; audioEssencePtr = audioEssencePtr->next ) { + + aafiAudioEssenceFile *audioEssenceFile = audioClip->essencePointerList->essenceFile; + + uint64_t sampleOffset = aafi_convertUnitUint64( audioClip->essence_offset, audioClip->track->edit_rate, audioEssenceFile->samplerateRational ); + uint64_t sampleLength = aafi_convertUnitUint64( audioClip->len, audioClip->track->edit_rate, audioEssenceFile->samplerateRational ); + + char *name = NULL; + char *usable_file_path = NULL; + + laaf_util_snprintf_realloc( &name, NULL, 0, "%i_%i_%s", audioClip->track->number, aafi_get_clipIndex(audioClip), audioClip->essencePointerList->essenceFile->unique_name ); + + if ( (rc += aafi_extractAudioEssenceFile( aafi, audioEssenceFile, extractFormat, outpath, sampleOffset, sampleLength, name, &usable_file_path )) == 0 ) { + success( "Audio clip file extracted to %s\"%s\"%s", + ANSI_COLOR_DARKGREY(aafi->log), + usable_file_path, + ANSI_COLOR_RESET(aafi->log) ); + } + else { + error( "Audio clip file extraction failed : %s\"%s\"%s", ANSI_COLOR_DARKGREY(aafi->log), name, ANSI_COLOR_RESET(aafi->log) ); + } + + free( usable_file_path ); + free( name ); + + usable_file_path = NULL; + name = NULL; + } + + return rc; +} + + + +static int set_audioEssenceWithRIFF( AAF_Iface *aafi, const char *filename, aafiAudioEssenceFile *audioEssenceFile, struct RIFFAudioFile *RIFFAudioFile, int isExternalFile ) +{ + if ( RIFFAudioFile->sampleCount >= INT64_MAX ) { + error( "%s : summary sample count is bigger than INT64_MAX (%"PRIu64")", audioEssenceFile->usable_file_path, RIFFAudioFile->sampleCount ); + return -1; + } + + if ( RIFFAudioFile->sampleRate >= INT_MAX ) { + error( "%s : summary sample rate is bigger than INT_MAX (%li)", audioEssenceFile->usable_file_path, RIFFAudioFile->sampleRate ); + return -1; + } + + if ( audioEssenceFile->channels > 0 && audioEssenceFile->channels != RIFFAudioFile->channels ) { + warning( "%s : summary channel count (%i) mismatch %s (%i)", filename, audioEssenceFile->channels, ((isExternalFile) ? "located file" : "previously retrieved data"), RIFFAudioFile->channels ); + } + // else { + // /* In Davinci Resolve embedded multichannel WAV, summary channel is always 1 */ + // audioEssenceFile->channels = RIFFAudioFile->channels; + // } + + if ( audioEssenceFile->samplerate > 0 && audioEssenceFile->samplerate != RIFFAudioFile->sampleRate ) { + warning( "%s : summary samplerate (%i) mismatch %s (%i)", filename, audioEssenceFile->samplerate, ((isExternalFile) ? "located file" : "previously retrieved data"), RIFFAudioFile->sampleRate ); + } + + if ( audioEssenceFile->samplesize > 0 && audioEssenceFile->samplesize != RIFFAudioFile->sampleSize ) { + warning( "%s : summary samplesize (%i) mismatch %s (%i)", filename , audioEssenceFile->samplesize, ((isExternalFile) ? "located file" : "previously retrieved data"), RIFFAudioFile->sampleSize ); + } + + if ( audioEssenceFile->length > 0 && (uint64_t)audioEssenceFile->length != RIFFAudioFile->sampleCount ) { + warning( "%s : summary samplecount (%"PRIi64") mismatch %s (%"PRIi64")", filename , audioEssenceFile->length, ((isExternalFile) ? "located file" : "previously retrieved data"), RIFFAudioFile->sampleCount ); + } + + audioEssenceFile->channels = RIFFAudioFile->channels; + audioEssenceFile->samplerate = RIFFAudioFile->sampleRate; + audioEssenceFile->samplesize = RIFFAudioFile->sampleSize; + + audioEssenceFile->length = (aafPosition_t)RIFFAudioFile->sampleCount; + audioEssenceFile->pcm_audio_start_offset = (uint64_t)RIFFAudioFile->pcm_audio_start_offset; + audioEssenceFile->samplerateRational->numerator = (int32_t)audioEssenceFile->samplerate; + + audioEssenceFile->samplerateRational->denominator = 1; + + + return 0; +} + + + +int aafi_parse_audio_essence( AAF_Iface *aafi, aafiAudioEssenceFile *audioEssenceFile ) +{ + int rc = 0; + uint64_t dataStreamSize = 0; + unsigned char *dataStream = NULL; + FILE *fp = NULL; + struct RIFFAudioFile RIFFAudioFile; + + + /* try audioEssenceFile->summary first, for both embedded and external */ + + if ( audioEssenceFile->summary ) { + + rc = laaf_riff_parseAudioFile( &RIFFAudioFile, RIFF_PARSE_AAF_SUMMARY, &embeddedAudioDataReaderCallback, audioEssenceFile->summary->val, &audioEssenceFile->summary->len, aafi, aafi->log ); + + if ( rc < 0 ) { + + if ( !audioEssenceFile->is_embedded && !audioEssenceFile->usable_file_path ) { + warning( "Could not parse essence summary of \"%s\".", audioEssenceFile->name ); + goto err; + } + + warning( "Could not parse essence summary of \"%s\". %s", + audioEssenceFile->name, + (audioEssenceFile->is_embedded) ? "Trying essence data stream." : + (audioEssenceFile->usable_file_path) ? "Trying external essence file." : " WTF ???" ); + } + else { + + if ( set_audioEssenceWithRIFF( aafi, "AAF Summary", audioEssenceFile, &RIFFAudioFile, 0 ) < 0 ) { + goto err; + } + + if ( !RIFFAudioFile.channels || + !RIFFAudioFile.sampleRate || + !RIFFAudioFile.sampleSize || + !RIFFAudioFile.sampleCount ) + { + /* + * Adobe Premiere Pro AIFC/WAVE Summaries of external files are missing + * SSND chunk/DATA chunk size (RIFFAudioFile.sampleCount) + */ + + if ( !audioEssenceFile->is_embedded && !audioEssenceFile->usable_file_path ) { + warning( "Summary of \"%s\" is missing some data.", audioEssenceFile->name ); + goto err; + } + + warning( "Summary of \"%s\" is missing some data. %s", + audioEssenceFile->name, + (audioEssenceFile->is_embedded) ? "Trying essence data stream." : + (audioEssenceFile->usable_file_path) ? "Trying external essence file." : " WTF ???" ); + } + else { + goto end; + } + } + } + else if ( audioEssenceFile->is_embedded ) { + warning( "Embedded audio essence \"%s\" has no summary. Trying essence data stream.", audioEssenceFile->name ); + } + else if ( audioEssenceFile->usable_file_path ) { + warning( "External audio essence \"%s\" has no summary. Trying external file.", audioEssenceFile->name ); + } + + + if ( audioEssenceFile->is_embedded ) { + + cfb_getStream( aafi->aafd->cfbd, audioEssenceFile->node, &dataStream, &dataStreamSize ); + + if ( dataStream == NULL ) { + error( "Could not retrieve audio essence stream from CFB" ); + goto err; + } + + rc = laaf_riff_parseAudioFile( &RIFFAudioFile, RIFF_PARSE_AAF_SUMMARY, &embeddedAudioDataReaderCallback, dataStream, &dataStreamSize, aafi, aafi->log ); + + if ( rc < 0 ) { + warning( "Could not parse embedded essence stream of \"%s\".", audioEssenceFile->name ); + goto err; + } + + if ( set_audioEssenceWithRIFF( aafi, "AAF Embedded stream", audioEssenceFile, &RIFFAudioFile, 0 ) < 0 ) { + goto err; + } + + goto end; + } + + + + if ( laaf_util_is_fileext( audioEssenceFile->usable_file_path, "wav" ) || + laaf_util_is_fileext( audioEssenceFile->usable_file_path, "wave" ) || + laaf_util_is_fileext( audioEssenceFile->usable_file_path, "aif" ) || + laaf_util_is_fileext( audioEssenceFile->usable_file_path, "aiff" ) || + laaf_util_is_fileext( audioEssenceFile->usable_file_path, "aifc" ) ) + { + fp = fopen( audioEssenceFile->usable_file_path, "rb" ); + + if ( fp == NULL ) { + error( "Could not open external audio essence file for reading : %s", audioEssenceFile->usable_file_path ); + goto err; + } + + + rc = laaf_riff_parseAudioFile( &RIFFAudioFile, 0, &externalAudioDataReaderCallback, fp, audioEssenceFile->usable_file_path, aafi, aafi->log ); + + if ( rc < 0 ) { + error( "Failed parsing external audio essence file : %s", audioEssenceFile->usable_file_path ); + goto err; + } + + if ( set_audioEssenceWithRIFF( aafi, audioEssenceFile->usable_file_path, audioEssenceFile, &RIFFAudioFile, 1 ) < 0 ) { + goto err; + } + } + else { + /* + * should be considered as a non-pcm audio format + * +│ 04317│├──◻ AAFClassID_TimelineMobSlot [slot:6 track:4] (DataDef : AAFDataDef_Sound) : Audio 4 - Layered Audio Editing +│ 01943││ └──◻ AAFClassID_Sequence +│ 02894││ └──◻ AAFClassID_SourceClip +│ 02899││ └──◻ AAFClassID_MasterMob (UsageCode: n/a) : speech-sample +│ 04405││ └──◻ AAFClassID_TimelineMobSlot [slot:1 track:1] (DataDef : AAFDataDef_Sound) +│ 03104││ └──◻ AAFClassID_SourceClip +│ 04140││ └──◻ AAFClassID_SourceMob (UsageCode: n/a) : speech-sample +│ 01287││ └──◻ AAFClassID_PCMDescriptor +│ 01477││ └──◻ AAFClassID_NetworkLocator : file:///C:/Users/user/Desktop/libAAF/test/res/speech-sample.mp3 + * + */ + + audioEssenceFile->type = AAFI_ESSENCE_TYPE_UNK; + } + + + rc = 0; + goto end; + +err: + rc = -1; + +end: + free( dataStream ); + + if ( fp ) + fclose( fp ); + + return rc; +} + + + +static size_t embeddedAudioDataReaderCallback( unsigned char *buf, size_t offset, size_t reqlen, void *user1, void *user2, void *user3 ) +{ + unsigned char *data = user1; + size_t datasz = *(size_t*)user2; + AAF_Iface *aafi = (AAF_Iface*)user3; + + if ( offset > datasz ) { + error( "Requested data starts beyond data length" ); + return RIFF_READER_ERROR; + } + + if ( offset+reqlen > datasz ) { + reqlen = datasz - (offset+reqlen); + } + + memcpy( buf, data+offset, reqlen ); + + return reqlen; +} + + + +static size_t externalAudioDataReaderCallback( unsigned char *buf, size_t offset, size_t reqlen, void *user1, void *user2, void *user3 ) +{ + FILE *fp = (FILE*)user1; + const char *filename = (const char*)user2; + AAF_Iface *aafi = (AAF_Iface*)user3; + +#ifdef _WIN32 + assert( offset < _I64_MAX ); + + if ( _fseeki64( fp, (__int64)offset, SEEK_SET ) < 0 ) { + error( "Could not seek to %"PRIu64" in file '%s' : %s", offset, filename, strerror(errno) ); + return RIFF_READER_ERROR; + } +#else + assert( offset < LONG_MAX ); + + if ( fseek( fp, (long)offset, SEEK_SET ) < 0 ) { + error( "Could not seek to %"PRIu64" in file '%s' : %s", offset, filename, strerror(errno) ); + return RIFF_READER_ERROR; + } +#endif + + size_t byteRead = fread( buf, sizeof(unsigned char), reqlen, fp ); + + if ( feof(fp) ) { + if ( byteRead < reqlen ) { + error( "Incomplete fread() of '%s' due to EOF : %"PRIu64" bytes read out of %"PRIu64" requested", filename, byteRead, reqlen ); + return RIFF_READER_ERROR; + } + debug( "fread() : EOF reached in file '%s'", filename ); + } + else if ( ferror(fp) ) { + if ( byteRead < reqlen ) { + error( "Incomplete fread() of '%s' due to error : %"PRIu64" bytes read out of %"PRIu64" requested", filename, byteRead, reqlen ); + } + else { + error( "fread() error of '%s' : %"PRIu64" bytes read out of %"PRIu64" requested", filename, byteRead, reqlen ); + } + return RIFF_READER_ERROR; + } + + return byteRead; +} diff --git a/src/AAFIface/AAFIParser.c b/src/AAFIface/AAFIParser.c index 14cd07f..27c1b72 100644 --- a/src/AAFIface/AAFIParser.c +++ b/src/AAFIface/AAFIParser.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -39,51 +39,43 @@ #include #include #include -#include #include -#include - #include - -#include -#include -#include -#include -#include -#include - -#include -#include - +#include #include #include -// #include #include #include #include #include #include #include -// #include #include -// #include + +#include +#include +#include +#include +#include + +#include +#include +#include #include +#include #define debug( ... ) \ - _dbg( aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) #define warning( ... ) \ - _dbg( aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) #define error( ... ) \ - _dbg( aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) - -// #define trace( ... ) -// _dbg( aafi->dbg, aafi, LIB_AAF_IFACE_TRACE, 0, __VA_ARGS__ ) + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) @@ -91,3383 +83,2057 @@ static aafRational_t AAFI_DEFAULT_TC_EDIT_RATE = { 25, 1 }; -#define RESET_CONTEXT( ctx ) \ - /*ctx.MobSlot = NULL;*/ \ - ctx.current_track = NULL; \ - /*ctx.current_pos = 0;*/ \ - ctx.current_transition = NULL; \ - ctx.current_clip_gain = NULL; \ - ctx.current_clip_automation = NULL; \ - ctx.current_essence = NULL; \ - ctx.current_clip = NULL; \ +#define RESET_CTX__AudioGain( ctx ) \ ctx.current_clip_is_muted = 0; \ + ctx.current_clip_gain = NULL; \ + ctx.current_clip_gain_is_used = 0; \ + ctx.current_clip_variable_gain = NULL; \ + ctx.current_clip_variable_gain_is_used = 0; + +#define RESET_CTX__AudioChannelCombiner( ctx ) \ ctx.current_clip_is_combined = 0; \ ctx.current_combined_clip_total_channel = 0; \ ctx.current_combined_clip_channel_num = 0; \ ctx.current_combined_clip_forced_length = 0; - // ctx.current_track_is_multichannel = 0; - // ctx.current_multichannel_track_channel = 0; - // ctx.current_multichannel_track_clip_length = 0; - +#define RESET_CONTEXT( ctx ) \ + ctx.current_track = NULL; \ + ctx.current_audio_essence = NULL; \ + ctx.current_clip = NULL; \ + RESET_CTX__AudioGain( ctx ); \ + RESET_CTX__AudioChannelCombiner( ctx ); +static int parse_Mob( AAF_Iface *aafi, aafObject *Mob, td *__ptd ); +static int parse_CompositionMob( AAF_Iface *aafi, aafObject *CompoMob, td *__ptd ); +static int parse_SourceMob( AAF_Iface *aafi, aafObject *SourceMob, td *__ptd ); +static int parse_MobSlot( AAF_Iface *aafi, aafObject *MobSlot, td *__ptd ); +static int parse_TimelineMobSlot( AAF_Iface *aafi, aafObject *TimelineMobSlot, td *__ptd ); +static int parse_EventMobSlot( AAF_Iface *aafi, aafObject *EventMobSlot, td *__ptd ); -// static void aafi_trace_obj( AAF_Iface *aafi, aafObject *Obj, char *color ); +static int parse_Component( AAF_Iface *aafi, aafObject *Component, td *__ptd ); +static int parse_Transition( AAF_Iface *aafi, aafObject *Transition, td *__ptd ); +static int parse_Segment( AAF_Iface *aafi, aafObject *Segment, td *__ptd ); -static wchar_t * build_unique_audiofilename( AAF_Iface *aafi, aafiAudioEssence *audioEssence ); -static wchar_t * build_unique_videofilename( AAF_Iface *aafi, aafiVideoEssence *videoEssence ); +static int parse_Filler( AAF_Iface *aafi, aafObject *Filler, td *__ptd ); +static int parse_SourceClip( AAF_Iface *aafi, aafObject *SourceClip, td *__ptd ); +static int parse_Timecode( AAF_Iface *aafi, aafObject *Timecode, td *__ptd ); +static int parse_DescriptiveMarker( AAF_Iface *aafi, aafObject *DescriptiveMarker, td *__ptd ); +static int parse_Sequence( AAF_Iface *aafi, aafObject *Sequence, td *__ptd ); +static int parse_Selector( AAF_Iface *aafi, aafObject *Selector, td *__ptd ); +static int parse_NestedScope( AAF_Iface *aafi, aafObject *NestedScope, td *__ptd ); +static int parse_OperationGroup( AAF_Iface *aafi, aafObject *OpGroup, td *__ptd ); -/* TODO move to AAFCore.c */ -static aafObject * get_Object_Ancestor( AAF_Iface *aafi, aafObject *Obj, const aafUID_t *ClassID ); +static int parse_Parameter( AAF_Iface *aafi, aafObject *Parameter, td *__ptd ); +static int parse_ConstantValue( AAF_Iface *aafi, aafObject *ConstantValue, td *__ptd ); +static int parse_VaryingValue( AAF_Iface *aafi, aafObject *VaryingValue, td *__ptd ); -static aafUID_t * get_Component_DataDefinition( AAF_Iface *aafi, aafObject *Component ); -// static aafUID_t * get_FileDescriptor_ContainerFormat( AAF_Iface *aafi, aafObject *FileDescriptor ); -static aafUID_t * get_OperationGroup_OperationIdentification( AAF_Iface *aafi, aafObject *OperationGroup ); -static aafUID_t * get_Parameter_InterpolationIdentification( AAF_Iface *aafi, aafObject *Parameter ); +static int parse_EssenceDescriptor( AAF_Iface *aafi, aafObject *EssenceDesc, td *__ptd ); +static int parse_PCMDescriptor( AAF_Iface *aafi, aafObject *PCMDescriptor, td *__ptd ); +static int parse_WAVEDescriptor( AAF_Iface *aafi, aafObject *WAVEDescriptor, td *__ptd ); +static int parse_AIFCDescriptor( AAF_Iface *aafi, aafObject *AIFCDescriptor, td *__ptd ); -static aafObject * get_EssenceData_By_MobID( AAF_Iface *aafi, aafMobID_t *MobID ); +static int parse_DigitalImageDescriptor( AAF_Iface *aafi, aafObject *DIDescriptor, td *__ptd ); +static int parse_CDCIDescriptor( AAF_Iface *aafi, aafObject *CDCIDescriptor, td *__ptd ); -// static aafiAudioEssence * getAudioEssenceBySourceMobID( AAF_Iface *aafi, aafMobID_t *sourceMobID ); -// static aafiVideoEssence * getVideoEssenceBySourceMobID( AAF_Iface *aafi, aafMobID_t *sourceMobID ); +static int parse_Locator( AAF_Iface *aafi, aafObject *Locator, td *__ptd ); +static int parse_NetworkLocator( AAF_Iface *aafi, aafObject *NetworkLocator, td *__ptd ); -static int parse_DigitalImageDescriptor( AAF_Iface *aafi, aafObject *DIDescriptor, td *__ptd ); -static int parse_CDCIDescriptor( AAF_Iface *aafi, aafObject *CDCIDescriptor, td *__ptd ); +static int parse_EssenceData( AAF_Iface *aafi, aafObject *EssenceData, td *__ptd ); -static int parse_EssenceDescriptor( AAF_Iface *aafi, aafObject *EssenceDesc, td *__ptd ); -static int parse_PCMDescriptor( AAF_Iface *aafi, aafObject *PCMDescriptor, td *__ptd ); -static int parse_WAVEDescriptor( AAF_Iface *aafi, aafObject *WAVEDescriptor, td *__ptd ); -static int parse_AIFCDescriptor( AAF_Iface *aafi, aafObject *AIFCDescriptor, td *__ptd ); +static int retrieve_UserComments( AAF_Iface *aafi, aafObject *UserComments, aafiMetaData **metadataList ); +static int retrieve_ControlPoints( AAF_Iface *aafi, aafObject *Points, aafRational_t *times[], aafRational_t *values[] ); -static int parse_Locator( AAF_Iface *aafi, aafObject *Locator, td *__ptd ); -static int parse_NetworkLocator( AAF_Iface *aafi, aafObject *NetworkLocator, td *__ptd ); -static int parse_EssenceData( AAF_Iface *aafi, aafObject *EssenceData, td *__ptd ); -static int parse_Component( AAF_Iface *aafi, aafObject *Component, td *__ptd ); -static int parse_Transition( AAF_Iface *aafi, aafObject *Transition, td *__ptd ); -static int parse_NestedScope( AAF_Iface *aafi, aafObject *NestedScope, td *__ptd ); -static int parse_Filler( AAF_Iface *aafi, aafObject *Filler, td *__ptd ); -static int parse_Sequence( AAF_Iface *aafi, aafObject *Sequence, td *__ptd ); -static int parse_Timecode( AAF_Iface *aafi, aafObject *Timecode, td *__ptd ); -static int parse_OperationGroup( AAF_Iface *aafi, aafObject *OpGroup, td *__ptd ); -static int parse_SourceClip( AAF_Iface *aafi, aafObject *SourceClip, td *__ptd ); -static int parse_Selector( AAF_Iface *aafi, aafObject *Selector, td *__ptd ); +/* **************************************************************************** + * M o b + * **************************************************************************** + * Mob (abs) + * | + * |--> CompositionMob + * |--> MasterMob + * `--> SourceMob + */ -static int parse_Parameter( AAF_Iface *aafi, aafObject *Parameter, td *__ptd ); -static int parse_ConstantValue( AAF_Iface *aafi, aafObject *ConstantValue, td *__ptd ); -static int parse_VaryingValue( AAF_Iface *aafi, aafObject *VaryingValue, td *__ptd ); -static int retrieve_ControlPoints( AAF_Iface *aafi, aafObject *Points, aafRational_t *times[], aafRational_t *values[] ); +static int parse_Mob( AAF_Iface *aafi, aafObject *Mob, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 1); -static int parse_Mob( AAF_Iface *aafi, aafObject *Mob ); -static int parse_CompositionMob( AAF_Iface *aafi, aafObject *CompoMob, td *__ptd ); -static int parse_SourceMob( AAF_Iface *aafi, aafObject *SourceMob, td *__ptd ); + int rc = 0; -static int parse_MobSlot( AAF_Iface *aafi, aafObject *MobSlot, td *__ptd ); + aafObject *MobSlots = aaf_get_propertyValue( Mob, PID_Mob_Slots, &AAFTypeID_MobSlotStrongReferenceVector ); -static void xplore_StrongObjectReferenceVector( AAF_Iface *aafi, aafObject *ObjCollection, td *__ptd ); + if ( !MobSlots ) { + TRACE_OBJ_ERROR( aafi, Mob, &__td, "Missing Mob::Slots" ); + goto err; + } + if ( aafUIDCmp( Mob->Class->ID, &AAFClassID_CompositionMob ) ) { + parse_CompositionMob( aafi, Mob, &__td ); + } + else if ( aafUIDCmp( Mob->Class->ID, &AAFClassID_SourceMob ) ) { + parse_SourceMob( aafi, Mob, &__td ); + } + else { + /* NOTE: MasterMob is accessed directly from parse_SourceClip() */ + TRACE_OBJ_NO_SUPPORT( aafi, Mob, &__td ); + } -static void xplore_StrongObjectReferenceVector( AAF_Iface *aafi, aafObject *ObjCollection, td *__ptd ) -{ - struct trace_dump __td; - __td_set(__td, __ptd, 0); + aafObject *MobSlot = NULL; - // aaf_dump_ObjectProperties( aafi->aafd, ComponentAttributeList ); + uint32_t i = 0; + AAFI_foreach_ObjectInSet( &MobSlot, MobSlots, i, __td ) { + parse_MobSlot( aafi, MobSlot, &__td ); + } - struct dbg *dbg = aafi->dbg; - aafObject *Obj = NULL; + goto end; - aaf_foreach_ObjectInSet( &Obj, ObjCollection, NULL ) { - // aaf_dump_ObjectProperties( aafi->aafd, ObjCollection ); - /* TODO implement retrieve_TaggedValue() */ +err: + rc = -1; - if ( aaf_get_property( Obj, PID_TaggedValue_Name ) && - aaf_get_property( Obj, PID_TaggedValue_Value ) ) - { - wchar_t *name = aaf_get_propertyValue( Obj, PID_TaggedValue_Name, &AAFTypeID_String ); - aafIndirect_t *indirect = aaf_get_propertyValue( Obj, PID_TaggedValue_Value, &AAFTypeID_Indirect ); +end: + return rc; +} - if ( aafUIDCmp( &indirect->TypeDef, &AAFTypeID_Int32 ) ) { - int32_t *indirectValue = aaf_get_indirectValue( aafi->aafd, indirect, &AAFTypeID_Int32 ); - DBG_BUFFER_WRITE( dbg, "Tagged | Name: %ls%*s Value (%ls) : %i\n", name, 56-(int)wcslen(name), " ", aaft_TypeIDToText(&indirect->TypeDef), *indirectValue ); - } - else - if ( aafUIDCmp( &indirect->TypeDef, &AAFTypeID_String ) ) { - wchar_t *indirectValue = aaf_get_indirectValue( aafi->aafd, indirect, &AAFTypeID_String ); - DBG_BUFFER_WRITE( dbg, "Tagged | Name: %ls%*s Value (%ls) : %ls\n", name, 56-(int)wcslen(name), " ", aaft_TypeIDToText(&indirect->TypeDef), indirectValue ); - free( indirectValue ); - } - else { - DBG_BUFFER_WRITE( dbg, "Tagged | Name: %ls%*s Value (%s%ls%s) : %sUNKNOWN_TYPE%s\n", name, 56-(int)wcslen(name), " ", ANSI_COLOR_RED(dbg), aaft_TypeIDToText(&indirect->TypeDef), ANSI_COLOR_RESET(dbg), ANSI_COLOR_RED(dbg), ANSI_COLOR_RESET(dbg) ); - } - dbg->debug_callback( dbg, (void*)aafi, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); - free( name ); - } - else { - dbg->debug_callback( dbg, (void*)aafi, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); - aaf_dump_ObjectProperties( aafi->aafd, Obj ); - } - } -} +static int parse_CompositionMob( AAF_Iface *aafi, aafObject *CompoMob, td *__ptd ) +{ + struct trace_dump __td; + __td_set( __td, __ptd, 0); + aafUID_t *UsageCode = aaf_get_propertyValue( CompoMob, PID_Mob_UsageCode, &AAFTypeID_UsageType ); -void aafi_dump_obj( AAF_Iface *aafi, aafObject *Obj, struct trace_dump *__td, int state, int line, const char *fmt, ... ) -{ - if ( aafi->ctx.options.trace == 0 ) - return; - /* Print caller line number */ - struct dbg *dbg = aafi->dbg; + if ( ( aafUIDCmp( aafi->aafd->Header.OperationalPattern, &AAFOPDef_EditProtocol ) && aafUIDCmp( UsageCode, &AAFUsage_TopLevel )) || + (!aafUIDCmp( aafi->aafd->Header.OperationalPattern, &AAFOPDef_EditProtocol ) && (aafUIDCmp( UsageCode, &AAFUsage_TopLevel ) || !UsageCode)) ) + { + aafi->ctx.TopLevelCompositionMob = CompoMob; + aafi->compositionName = aaf_get_propertyValue( CompoMob, PID_Mob_Name, &AAFTypeID_String ); - if ( Obj ) { + aafObject *UserComments = aaf_get_propertyValue( CompoMob, PID_Mob_UserComments, &AAFTypeID_TaggedValueStrongReferenceVector ); - switch ( state ) { - case TD_ERROR: DBG_BUFFER_WRITE( dbg, "%serr %s%ls %s", ANSI_COLOR_RED(dbg), ANSI_COLOR_DARKGREY(dbg), L"\u2502", ANSI_COLOR_RED(dbg) ); break; - case TD_WARNING: DBG_BUFFER_WRITE( dbg, "%swrn %s%ls %s", ANSI_COLOR_YELLOW(dbg), ANSI_COLOR_DARKGREY(dbg), L"\u2502", ANSI_COLOR_YELLOW(dbg) ); break; - case TD_NOT_SUPPORTED: DBG_BUFFER_WRITE( dbg, "%suns %s%ls %s", ANSI_COLOR_ORANGE(dbg), ANSI_COLOR_DARKGREY(dbg), L"\u2502", ANSI_COLOR_ORANGE(dbg) ); break; - default: DBG_BUFFER_WRITE( dbg, " %s%ls ", ANSI_COLOR_DARKGREY(dbg), L"\u2502" ); break; + if ( retrieve_UserComments( aafi, UserComments, &aafi->metadata ) < 0 ) { + TRACE_OBJ_WARNING( aafi, CompoMob, &__td, "Error parsing Mob::UserComments" ); + } else { + TRACE_OBJ( aafi, CompoMob, &__td ); } - DBG_BUFFER_WRITE( dbg, "%05i", line ); } else { - DBG_BUFFER_WRITE( dbg, " %s%ls%s ", ANSI_COLOR_DARKGREY(dbg), L"\u2502", ANSI_COLOR_RESET(dbg) ); + TRACE_OBJ_NO_SUPPORT( aafi, CompoMob, &__td ); } - DBG_BUFFER_WRITE( dbg, "%s%ls%s", ANSI_COLOR_DARKGREY(dbg), L"\u2502", ANSI_COLOR_RESET(dbg) ); // │ + return 0; +} - /* Print padding and vertical lines */ - if ( __td->lv > 0 ) { - for ( int i = 0; i < __td->lv; i++ ) { +static int parse_SourceMob( AAF_Iface *aafi, aafObject *SourceMob, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 0); - /* current level iteration has more than one entry remaining in loop */ - if ( __td->ll[i] > 1 ) { + aafMobID_t *MobID = aaf_get_propertyValue( SourceMob, PID_Mob_MobID, &AAFTypeID_MobIDType ); - /* next level iteration is current trace */ + if ( !MobID ) { + TRACE_OBJ_ERROR( aafi, SourceMob, &__td, "Missing Mob::MobID" ); + return -1; + } - if ( i+1 == __td->lv ) { - if ( Obj ) { - DBG_BUFFER_WRITE( dbg, "%ls", L"\u251c\u2500\u2500\u25fb " ); // ├──◻ - } - else { - DBG_BUFFER_WRITE( dbg, "%ls", L"\u2502 " ); // │ - } - } - else { - DBG_BUFFER_WRITE( dbg, "%ls", L"\u2502 " ); // │ - } - } - else if ( i+1 == __td->lv && Obj ) { - DBG_BUFFER_WRITE( dbg, "%ls", L"\u2514\u2500\u2500\u25fb " ); // └──◻ - } - else { - DBG_BUFFER_WRITE( dbg, " " ); - } - } + aafTimeStamp_t *CreationTime = aaf_get_propertyValue( SourceMob, PID_Mob_CreationTime, &AAFTypeID_TimeStamp ); + + if ( !CreationTime ) { + TRACE_OBJ_ERROR( aafi, SourceMob, &__td, "Missing Mob::CreationTime" ); + return -1; } + aafObject *EssenceDesc = aaf_get_propertyValue( SourceMob, PID_SourceMob_EssenceDescription, &AAFTypeID_EssenceDescriptorStrongReference ); - if ( Obj ) { + if ( !EssenceDesc ) { + TRACE_OBJ_ERROR( aafi, SourceMob, &__td, "Missing SourceMob::EssenceDescription" ); + return -1; + } - switch ( state ) { - case TD_ERROR: DBG_BUFFER_WRITE( dbg, "%s", ANSI_COLOR_RED(dbg) ); break; - case TD_WARNING: DBG_BUFFER_WRITE( dbg, "%s", ANSI_COLOR_YELLOW(dbg) ); break; - case TD_NOT_SUPPORTED: DBG_BUFFER_WRITE( dbg, "%s", ANSI_COLOR_ORANGE(dbg) ); break; - case TD_INFO: - case TD_OK: - if ( __td->sub ) { - DBG_BUFFER_WRITE( dbg, "%s", ANSI_COLOR_DARKGREY(dbg) ); - } else { - DBG_BUFFER_WRITE( dbg, "%s", ANSI_COLOR_CYAN(dbg) ); - } + TRACE_OBJ( aafi, SourceMob, &__td ); - break; - } + /* + * SourceMob can be parsed for Audio and Video. + * aafi->ctx.current_audio_essence is set, it means we are parsing Audio, so + * we need to retrieve more data. + */ - DBG_BUFFER_WRITE( dbg, "%ls ", aaft_ClassIDToText(aafi->aafd, Obj->Class->ID) ); + if ( aafi->ctx.current_audio_essence ) { - DBG_BUFFER_WRITE( dbg, "%s", ANSI_COLOR_RESET(dbg) ); + aafiAudioEssenceFile *audioEssenceFile = (aafiAudioEssenceFile*)aafi->ctx.current_audio_essence; + memcpy( audioEssenceFile->umid, MobID, sizeof(aafMobID_t) ); - if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_TimelineMobSlot ) ) - { + int rc = snprintf( audioEssenceFile->originationDate, sizeof(((aafiAudioEssenceFile *)0)->originationDate), "%04u:%02u:%02u", + (CreationTime->date.year <= 9999) ? CreationTime->date.year : 0, + (CreationTime->date.month <= 99) ? CreationTime->date.month : 0, + (CreationTime->date.day <= 99) ? CreationTime->date.day : 0 ); - aafObject *Segment = aaf_get_propertyValue( Obj, PID_MobSlot_Segment, &AAFTypeID_SegmentStrongReference ); - aafUID_t *DataDefinition = get_Component_DataDefinition( aafi, Segment ); - wchar_t *name = aaf_get_propertyValue( Obj, PID_MobSlot_SlotName, &AAFTypeID_String ); - uint32_t *slotID = aaf_get_propertyValue( Obj, PID_MobSlot_SlotID, &AAFTypeID_UInt32 ); - uint32_t *trackNo = aaf_get_propertyValue( Obj, PID_MobSlot_PhysicalTrackNumber, &AAFTypeID_UInt32 ); + assert( rc > 0 && (size_t)rc < sizeof(((aafiAudioEssenceFile *)0)->originationDate) ); - DBG_BUFFER_WRITE( dbg, "[slot:%s%i%s track:%s%i%s] (DataDef : %s%ls%s) %s%ls ", - ANSI_COLOR_BOLD(dbg), - (slotID) ? (int)(*slotID) : -1, - ANSI_COLOR_RESET(dbg), - ANSI_COLOR_BOLD(dbg), - (trackNo) ? (int)(*trackNo) : -1, - ANSI_COLOR_RESET(dbg), - ANSI_COLOR_DARKGREY(dbg), - aaft_DataDefToText( aafi->aafd, DataDefinition ), - ANSI_COLOR_RESET(dbg), - (name && name[0] != 0x00) ? ": " : "", (name) ? name : L"" - ); + // if ( rc < 0 || (size_t)rc >= sizeof(((aafiAudioEssenceFile *)0)->originationDate) ) { + // fprintf( stderr, "snprintf() error" ); + // return -1; + // } - free( name ); - } - else - if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_CompositionMob ) || - aafUIDCmp( Obj->Class->ID, &AAFClassID_MasterMob ) || - aafUIDCmp( Obj->Class->ID, &AAFClassID_SourceMob ) ) - { - aafUID_t *usageCode = aaf_get_propertyValue( Obj, PID_Mob_UsageCode, &AAFTypeID_UsageType ); - wchar_t *name = aaf_get_propertyValue( Obj, PID_Mob_Name, &AAFTypeID_String ); + rc = snprintf( audioEssenceFile->originationTime, sizeof(((aafiAudioEssenceFile *)0)->originationTime), "%02u:%02u:%02u", + (CreationTime->time.hour <= 99) ? CreationTime->time.hour : 0, + (CreationTime->time.minute <= 99) ? CreationTime->time.minute : 0, + (CreationTime->time.second <= 99) ? CreationTime->time.second : 0 ); - DBG_BUFFER_WRITE( dbg, "(UsageCode: %s%ls%s) %s%ls", - ANSI_COLOR_DARKGREY(dbg), - aaft_UsageCodeToText( usageCode ), - ANSI_COLOR_RESET(dbg), - (name && name[0] != 0x00) ? ": " : "", (name) ? name : L"" - ); + assert( rc > 0 && (size_t)rc < sizeof(((aafiAudioEssenceFile *)0)->originationTime) ); - free( name ); - } - else if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_OperationGroup ) ) { + // if ( rc < 0 || (size_t)rc >= sizeof(((aafiAudioEssenceFile *)0)->originationTime) ) { + // fprintf( stderr, "snprintf() error" ); + // return -1; + // } + } - aafUID_t *OperationIdentification = get_OperationGroup_OperationIdentification( aafi, Obj ); + __td.ll[__td.lv] = 2; + parse_EssenceDescriptor( aafi, EssenceDesc, &__td ); + __td.ll[__td.lv] = 1; - int64_t *length = aaf_get_propertyValue( Obj, PID_Component_Length, &AAFTypeID_LengthType ); + return 0; +} - DBG_BUFFER_WRITE( dbg, "(OpIdent: %s%ls%s; Length: %s%li%s) ", - ANSI_COLOR_DARKGREY(dbg), - aaft_OperationDefToText( aafi->aafd, OperationIdentification ), - ANSI_COLOR_RESET(dbg), - ANSI_COLOR_DARKGREY(dbg), - (length) ? *length : -1, - ANSI_COLOR_RESET(dbg) - ); - } - else if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_Sequence ) || - aafUIDCmp( Obj->Class->ID, &AAFClassID_Filler ) || - aafUIDCmp( Obj->Class->ID, &AAFClassID_SourceClip ) || - aafUIDCmp( Obj->Class->ID, &AAFClassID_Selector ) || - aafUIDCmp( Obj->Class->ID, &AAFClassID_Transition ) ) - { - int64_t *length = aaf_get_propertyValue( Obj, PID_Component_Length, &AAFTypeID_LengthType ); - DBG_BUFFER_WRITE( dbg, "(Length: %s%li%s) ", - ANSI_COLOR_DARKGREY(dbg), - (length) ? *length : -1, - ANSI_COLOR_RESET(dbg) - ); - } - else if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_ConstantValue ) ) { +/* **************************************************************************** + * M o b S l o t + * **************************************************************************** + * + * MobSlot (abs) + * | + * |--> TimelineMobSlot + * |--> EventMobSlot + * `--> StaticMobSlot + */ - aafIndirect_t *Indirect = aaf_get_propertyValue( Obj, PID_ConstantValue_Value, &AAFTypeID_Indirect ); +static int parse_MobSlot( AAF_Iface *aafi, aafObject *MobSlot, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 1); - if ( Indirect ) { - aafRational_t *multiplier = aaf_get_indirectValue( aafi->aafd, Indirect, &AAFTypeID_Rational ); + aafObject *Segment = aaf_get_propertyValue( MobSlot, PID_MobSlot_Segment, &AAFTypeID_SegmentStrongReference ); - if ( multiplier ) { - DBG_BUFFER_WRITE( dbg, "(Value: %s%i/%i%s %+05.1lf dB) ", - ANSI_COLOR_DARKGREY(dbg), - multiplier->numerator, - multiplier->denominator, - 20 * log10( aafRationalToFloat( *multiplier ) ), - ANSI_COLOR_RESET(dbg) - ); - } - } - } - // else if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_TapeDescriptor ) || - // aafUIDCmp( Obj->Class->ID, &AAFClassID_FilmDescriptor ) || - // aafUIDCmp( Obj->Class->ID, &AAFClassID_CDCIDescriptor ) || - // aafUIDCmp( Obj->Class->ID, &AAFClassID_RGBADescriptor ) || - // aafUIDCmp( Obj->Class->ID, &AAFClassID_TIFFDescriptor ) || - // aafUIDCmp( Obj->Class->ID, &AAFClassID_SoundDescriptor ) || - // aafUIDCmp( Obj->Class->ID, &AAFClassID_PCMDescriptor ) || - // aafUIDCmp( Obj->Class->ID, &AAFClassID_AES3PCMDescriptor ) || - // aafUIDCmp( Obj->Class->ID, &AAFClassID_WAVEDescriptor ) || - // aafUIDCmp( Obj->Class->ID, &AAFClassID_AIFCDescriptor ) ) - // { - // aafUID_t *ContainerFormat = get_FileDescriptor_ContainerFormat( aafi, Obj ); - // DBG_BUFFER_WRITE( dbg, "(ContainerIdent : \x1b[38;5;242m%ls\x1b[0m)", aaft_ContainerToText(ContainerFormat) ); - // } + if ( !Segment ) { + TRACE_OBJ_ERROR( aafi, MobSlot, &__td, "Missing MobSlot::Segment" ); + return -1; + } - if ( state == TD_ERROR ) { - DBG_BUFFER_WRITE( dbg, ": %s", ANSI_COLOR_RED(dbg) ); + if ( aafUIDCmp( MobSlot->Class->ID, &AAFClassID_TimelineMobSlot ) ) { + if ( parse_TimelineMobSlot( aafi, MobSlot, &__td ) < 0 ) { + return -1; } - else if ( state == TD_INFO ) { - DBG_BUFFER_WRITE( dbg, ": %s", ANSI_COLOR_CYAN(dbg) ); + } + else if ( aafUIDCmp( MobSlot->Class->ID, &AAFClassID_EventMobSlot ) ) { + if ( parse_EventMobSlot( aafi, MobSlot, &__td ) < 0 ) { + return -1; } + } + else { + TRACE_OBJ_NO_SUPPORT( aafi, MobSlot, &__td ); + return -1; + } - va_list args; - va_start( args, fmt ); - dbg->_dbg_msg_pos += laaf_util_vsnprintf_realloc( &dbg->_dbg_msg, &dbg->_dbg_msg_size, dbg->_dbg_msg_pos, fmt, &args ); + parse_Segment( aafi, Segment, &__td ); - va_end( args ); - // va_list args; - // va_list args2; - // va_copy( args2, args ); - // - // va_start( args2, fmt ); - // // vprintf(fmt, args); - // // offset += laaf_util_vsnprintf_realloc( &dbg->_dbg_msg, &dbg->_dbg_msg_size, offset, fmt, args ); - // int needed = vsnprintf( NULL, 0, fmt, args2 ) + 1; - // if ( needed >= dbg->_dbg_msg_size + offset ) { - // char *p = realloc( dbg->_dbg_msg, offset+needed ); - // if (p) { - // dbg->_dbg_msg = p; - // } else { - // /* TODO: realloc() faillure */ - // // free(*str); - // // *str = NULL; - // // *size = 0; - // // return -1; - // } - // } - // va_end( args2 ); - // - // va_start( args, fmt ); - // // vprintf( fmt, args ); - // offset += vsnprintf( dbg->_dbg_msg+offset, dbg->_dbg_msg_size-offset, fmt, args ); - // va_end( args ); + return 0; +} - if ( state == TD_ERROR || state == TD_INFO ) { - DBG_BUFFER_WRITE( dbg, "." ); - } - if ( !aafi->ctx.options.dump_class_aaf_properties ) { - aafProperty * Prop = NULL; - int hasUnknownProps = 0; - for ( Prop = Obj->Properties; Prop != NULL; Prop = Prop->next ) { +static int parse_TimelineMobSlot( AAF_Iface *aafi, aafObject *TimelineMobSlot, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 0); - if ( Prop->def->meta ) { - // DBG_BUFFER_WRITE( dbg, "\n"); + aafObject *ParentMob = aaf_get_ObjectAncestor( TimelineMobSlot, &AAFClassID_Mob ); - if ( aafi->ctx.options.trace_meta ) { - // aaf_dump_ObjectProperties( aafi->aafd, Obj ); + if ( !ParentMob ) { + TRACE_OBJ_ERROR( aafi, TimelineMobSlot, &__td, "Could not retrieve parent Mob" ); + return -1; + } - // if ( Prop->pid == 0xffca ) { - if ( Prop->sf == SF_STRONG_OBJECT_REFERENCE_VECTOR ) { - DBG_BUFFER_WRITE( dbg, "\n" ); - DBG_BUFFER_WRITE( dbg, " >>> (0x%04x) %ls (%ls)\n", Prop->pid, aaft_PIDToText( aafi->aafd, Prop->pid ), aaft_StoredFormToText( Prop->sf ) /*AUIDToText( &Prop->def->type ),*/ /*aaft_TypeIDToText( &(Prop->def->type) )*/ ); - void *propValue = aaf_get_propertyValue( Obj, Prop->pid, &AAFUID_NULL ); - xplore_StrongObjectReferenceVector( aafi, propValue, __td ); + uint32_t *track_num = aaf_get_propertyValue( TimelineMobSlot, PID_MobSlot_PhysicalTrackNumber, &AAFTypeID_UInt32 ); - // DUMP_OBJ_NO_SUPPORT( aafi, propValue, __td ); - } - else { - DBG_BUFFER_WRITE( dbg, "\n" ); - aaf_dump_ObjectProperty( aafi->aafd, Prop ); - } - } - else { - DBG_BUFFER_WRITE( dbg, "%s%s %ls[0x%04x]", ANSI_COLOR_RESET(dbg), (!hasUnknownProps) ? " (MetaProps:" : "", aaft_PIDToText( aafi->aafd, Prop->pid ), Prop->pid ); - // laaf_util_dump_hex( Prop->val, Prop->len ); - hasUnknownProps++; - } - } - } - if ( aafi->ctx.options.trace_meta == 0 && hasUnknownProps ) { - DBG_BUFFER_WRITE( dbg, ")" ); - } - } + if ( !track_num ) { + debug( "Missing MobSlot::PhysicalTrackNumber" ); + } + aafObject *Segment = aaf_get_propertyValue( TimelineMobSlot, PID_MobSlot_Segment, &AAFTypeID_SegmentStrongReference ); - if ( aafi->ctx.options.dump_class_raw_properties && wcscmp( aaft_ClassIDToText(aafi->aafd, Obj->Class->ID), aafi->ctx.options.dump_class_raw_properties ) == 0 ) { - DBG_BUFFER_WRITE( dbg, "\n\n" ); - DBG_BUFFER_WRITE( dbg, "======================================================================\n" ); - DBG_BUFFER_WRITE( dbg, " CFB Object Properties Dump\n" ); - DBG_BUFFER_WRITE( dbg, "======================================================================\n" ); - DBG_BUFFER_WRITE( dbg, "%s", ANSI_COLOR_DARKGREY(dbg) ); - DBG_BUFFER_WRITE( dbg, "%ls\n", aaft_ClassIDToText(aafi->aafd, Obj->Class->ID) ); - DBG_BUFFER_WRITE( dbg, "%ls/properties\n", aaf_get_ObjectPath( Obj ) ); - DBG_BUFFER_WRITE( dbg, "%s\n\n", ANSI_COLOR_RESET(dbg) ); + if ( !Segment ) { + TRACE_OBJ_ERROR( aafi, TimelineMobSlot, &__td, "Missing MobSlot::Segment" ); + return -1; + } - // cfb_dump_node( aafi->aafd->cfbd, cfb_getChildNode( aafi->aafd->cfbd, L"properties", Obj->Node ), 1 ); - aaf_dump_nodeStreamProperties( aafi->aafd, cfb_getChildNode( aafi->aafd->cfbd, L"properties", Obj->Node ) ); + aafWeakRef_t *dataDefWeakRef = aaf_get_propertyValue( Segment, PID_Component_DataDefinition, &AAFTypeID_DataDefinitionWeakReference ); - DBG_BUFFER_WRITE( dbg, "\n" ); - } + if ( !dataDefWeakRef ) { + TRACE_OBJ_ERROR( aafi, Segment, &__td, "Could not retrieve Component::DataDefinition from Segment child" ); + return -1; + } - if ( aafi->ctx.options.dump_class_aaf_properties && wcscmp( aaft_ClassIDToText(aafi->aafd, Obj->Class->ID), aafi->ctx.options.dump_class_aaf_properties ) == 0 ) { - DBG_BUFFER_WRITE( dbg, "\n\n" ); - DBG_BUFFER_WRITE( dbg, "======================================================================\n" ); - DBG_BUFFER_WRITE( dbg, " AAF Properties Dump\n" ); - DBG_BUFFER_WRITE( dbg, "======================================================================\n" ); - DBG_BUFFER_WRITE( dbg, "%s", ANSI_COLOR_DARKGREY(dbg) ); - DBG_BUFFER_WRITE( dbg, "%ls\n", aaft_ClassIDToText(aafi->aafd, Obj->Class->ID) ); - DBG_BUFFER_WRITE( dbg, "%ls/properties\n", aaf_get_ObjectPath( Obj ) ); - DBG_BUFFER_WRITE( dbg, "%s\n\n", ANSI_COLOR_RESET(dbg) ); + aafUID_t *DataDefinition = aaf_get_DataIdentificationByWeakRef( aafi->aafd, dataDefWeakRef ); - aaf_dump_ObjectProperties( aafi->aafd, Obj ); + if ( !DataDefinition ) { + TRACE_OBJ_ERROR( aafi, TimelineMobSlot, &__td, "Could not retrieve DataDefinition" ); + return -1; + } - DBG_BUFFER_WRITE( dbg, "\n" ); - } + aafRational_t *edit_rate = aaf_get_propertyValue( TimelineMobSlot, PID_TimelineMobSlot_EditRate, &AAFTypeID_Rational ); - DBG_BUFFER_WRITE( dbg, "%s", ANSI_COLOR_RESET(dbg) ); + if ( !edit_rate ) { + TRACE_OBJ_ERROR( aafi, TimelineMobSlot, &__td, "Missing TimelineMobSlot::EditRate" ); + return -1; } - // DBG_BUFFER_WRITE( dbg, "\n" ); + if ( aafUIDCmp( ParentMob->Class->ID, &AAFClassID_CompositionMob ) ) { - dbg->debug_callback( dbg, (void*)aafi, DEBUG_SRC_ID_TRACE, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + /* + * Each TimelineMobSlot represents a track, either audio or video. + * + * The Timeline MobSlot::Segment should hold a Sequence of Components. + * This Sequence represents the timeline track. Therefore, each SourceClip + * contained in the Sequence::Components represents a clip on the timeline. + * + * CompositionMob can have TimelineMobSlots, StaticMobSlots, EventMobSlots + */ + /* + * TODO: implement multiple TopLevel compositions support + */ - /* if end of branch, print one line padding */ - if ( Obj && ( __td->eob || state == TD_ERROR ) ) - aafi_dump_obj( aafi, NULL, __td, 0, -1, "" ); -} + if ( aafUIDCmp( DataDefinition, &AAFDataDef_Sound ) || + aafUIDCmp( DataDefinition, &AAFDataDef_LegacySound ) ) + { + /* + * « In a CompositionMob or MasterMob, PhysicalTrackNumber is the output + * channel number that the MobSlot should be routed to when played. » + */ + if ( aafi->ctx.TopLevelCompositionMob == ParentMob /*!parentMobUsageCode || aafUIDCmp( parentMobUsageCode, &AAFUsage_TopLevel )*/ /*!aafi->ctx.is_inside_derivation_chain*/ ) { -void aafi_dump_obj_no_support( AAF_Iface *aafi, aafObject *Obj, struct trace_dump *__td, int line ) -{ + TRACE_OBJ( aafi, TimelineMobSlot, &__td ); - // aafUID_t *DataDefinition = NULL; - if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_TimelineMobSlot ) && - aafUIDCmp( Obj->Parent->Class->ID, &AAFClassID_CompositionMob ) ) - { - /* this part is handled by aafi_dump_obj() already. */ - aafi_dump_obj( aafi, Obj, __td, TD_NOT_SUPPORTED, line, "" ); - return; - // aafObject *Segment = aaf_get_propertyValue( Obj, PID_MobSlot_Segment, &AAFTypeID_SegmentStrongReference ); - // - // if ( Segment != NULL ) /* req */ { - // DataDefinition = get_Component_DataDefinition( aafi, Segment ); - // } - // } - // else { - // DataDefinition = get_Component_DataDefinition( aafi, Obj ); - } - - // DataDefinition = get_Component_DataDefinition( aafi, Obj ); + uint32_t tracknumber = (track_num) ? *track_num : (aafi->Audio->track_count + 1); + aafiAudioTrack *track = aafi_newAudioTrack( aafi ); - aafi_dump_obj( aafi, Obj, __td, TD_NOT_SUPPORTED, line, "" ); - - // aafi_dump_obj( aafi, Obj, __td, WARNING, line, "%s%ls%s", - // // aaft_ClassIDToText( aafi->aafd, Obj->Class->ID ), - // ((DataDefinition) ? "(Segment DataDefinition: \x1b[38;5;242m" : ""), - // ((DataDefinition) ? aaft_DataDefToText( aafi->aafd, DataDefinition ) : L""), - // ((DataDefinition) ? ") \x1b[0m" : "") ); + track->number = tracknumber; + track->name = aaf_get_propertyValue( TimelineMobSlot, PID_MobSlot_SlotName, &AAFTypeID_String ); + track->edit_rate = edit_rate; -} + aafi->Audio->track_count += 1; + aafi->ctx.current_track = track; -/* -#define DUMP_OBJ( aafi, Obj, __td ) \ - aafi_dump_obj( aafi, Obj, __td, OK, __LINE__, "" ); -#define DUMP_OBJ_ERROR( aafi, Obj, __td, ... ) \ - (__td)->eob = 1; \ - aafi_dump_obj( aafi, Obj, __td, ERROR, __LINE__, __VA_ARGS__ ); + /* + * Avid Media Composer + */ -#define DUMP_OBJ_WARNING( aafi, Obj, __td, ... ) \ - aafi_dump_obj( aafi, Obj, __td, WARNING, __LINE__, __VA_ARGS__ ); + void *TimelineMobAttributeList = aaf_get_propertyValue( TimelineMobSlot, aaf_get_PropertyIDByName( aafi->aafd, "TimelineMobAttributeList" ), &AAFTypeID_TaggedValueStrongReferenceVector ); -#define DUMP_OBJ_INFO( aafi, Obj, __td, ... ) \ - aafi_dump_obj( aafi, Obj, __td, OK, __LINE__, __VA_ARGS__ ); + if ( TimelineMobAttributeList ) { -#define DUMP_OBJ_NO_SUPPORT( aafi, Obj, __td ) \ - (__td)->eob = 1; \ - aafi_dump_obj_no_support( aafi, Obj, __td, __LINE__ ); \ - // aaf_dump_ObjectProperties( aafi->aafd, Obj ); -*/ + int32_t *solo = aaf_get_TaggedValueByName( aafi->aafd, TimelineMobAttributeList, "AudioMixerCompSolo", &AAFTypeID_Int32 ); + int32_t *mute = aaf_get_TaggedValueByName( aafi->aafd, TimelineMobAttributeList, "AudioMixerCompMute", &AAFTypeID_Int32 ); + if ( solo && *solo ) { + track->solo = 1; + } + if ( mute && *mute ) { + track->mute = 1; + } + } + } + else { + TRACE_OBJ( aafi, TimelineMobSlot, &__td ); + } + } + else if ( aafUIDCmp( DataDefinition, &AAFDataDef_Picture ) || + aafUIDCmp( DataDefinition, &AAFDataDef_LegacyPicture ) ) + { + if ( aafi->Video->Tracks ) { + TRACE_OBJ_ERROR( aafi, TimelineMobSlot, &__td, "Current implementation supports only one video track" ); + return -1; + } -static wchar_t * build_unique_audiofilename( AAF_Iface *aafi, aafiAudioEssence *audioEssence ) -{ - wchar_t *unique = NULL; - size_t unique_size = 0; - size_t file_name_len = 0; + TRACE_OBJ( aafi, TimelineMobSlot, &__td ); - if ( audioEssence->file_name ) { - file_name_len = wcslen( audioEssence->file_name ); - unique_size = file_name_len +1 +4; // +4 = "_001" - unique_size = (unique_size < AAFUID_PRINTED_LEN+1) ? AAFUID_PRINTED_LEN+1 : unique_size; + uint32_t tracknumber = (track_num) ? *track_num : 1 /* current implementation supports only one video track */; - // debug("%lu, %lu", file_name_len, unique_size); - unique = malloc( sizeof(wchar_t) * unique_size ); + aafiVideoTrack *track = aafi_newVideoTrack( aafi ); - if ( unique == NULL ) { - error( "Could not allocate memory : %s", strerror(errno) ); - return NULL; + track->number = tracknumber; + track->name = aaf_get_propertyValue( TimelineMobSlot, PID_MobSlot_SlotName, &AAFTypeID_String ); + track->edit_rate = edit_rate; } - - if ( swprintf( unique, unique_size, L"%" WPRIws, audioEssence->file_name ) < 0 ) { - error( "Could not prepare unique filename" ); - return NULL; + else if ( aafUIDCmp( DataDefinition, &AAFDataDef_Timecode ) || + aafUIDCmp( DataDefinition, &AAFDataDef_LegacyTimecode ) ) + { + TRACE_OBJ( aafi, TimelineMobSlot, &__td ); } - } - else { - - file_name_len = strlen("unknown"); - unique_size = file_name_len +1 +4; // +4 = "_001" - unique_size = (unique_size < AAFUID_PRINTED_LEN+1) ? AAFUID_PRINTED_LEN+1 : unique_size; - - unique = malloc( sizeof(wchar_t) * unique_size ); + else if ( aafUIDCmp( DataDefinition, &AAFDataDef_DescriptiveMetadata ) ) { + /* + * Avid Media Composer 23.12, markers with duration (no-duration markers are held by AAFClassID_EventMobSlot) + * + │ 04179│ └──◻ AAFClassID_TimelineMobSlot [slot:3003 track:12] (DataDef: AAFDataDef_DescriptiveMetadata) : Segmentation + │ 01946│ └──◻ AAFClassID_Sequence (Length: 4) + │ 03031│ └──◻ AAFClassID_DescriptiveMarker (Length: 4) (MetaProps: CommentMarkerAttributeList[0xffd4] CommentMarkerColor[0xffdb] CommentMarkerUSer[0xffda] CommentMarkerDate[0xffd9] CommentMarkerTime[0xffd8]) + */ - if ( unique == NULL ) { - error( "Could not allocate memory : %s", strerror(errno) ); - return NULL; + TRACE_OBJ( aafi, TimelineMobSlot, &__td ); } - - if ( swprintf( unique, unique_size, L"unknown" ) < 0 ) { - error( "Could not prepare unique filename" ); - return NULL; + else { + TRACE_OBJ_NO_SUPPORT( aafi, TimelineMobSlot, &__td ); + return -1; } } + else if ( aafUIDCmp( ParentMob->Class->ID, &AAFClassID_MasterMob ) ) { + TRACE_OBJ( aafi, TimelineMobSlot, &__td ); + } + else if ( aafUIDCmp( ParentMob->Class->ID, &AAFClassID_SourceMob ) ) { - // debug( "%ls", unique ); + /* + * SourceMob can be parsed for Audio and Video. + * aafi->ctx.current_audio_essence is set, it means we are parsing Audio, so + * we need to retrieve more data. + */ - aafiAudioEssence *ae = NULL; + if ( aafi->ctx.current_audio_essence ) { - if ( aafi->ctx.options.forbid_nonlatin_filenames && laaf_util_wstr_contains_nonlatin( unique ) ) { + aafPosition_t *Origin = aaf_get_propertyValue( TimelineMobSlot, PID_TimelineMobSlot_Origin, &AAFTypeID_PositionType ); - aafUID_t *uuid = &(audioEssence->sourceMobID->material); + if ( !Origin ) { + TRACE_OBJ_ERROR( aafi, TimelineMobSlot, &__td, "Missing TimelineMobSlot::Origin" ); + return -1; + } - int rc = swprintf( unique, unique_size, L"%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", - uuid->Data1, - uuid->Data2, - uuid->Data3, - uuid->Data4[0], - uuid->Data4[1], - uuid->Data4[2], - uuid->Data4[3], - uuid->Data4[4], - uuid->Data4[5], - uuid->Data4[6], - uuid->Data4[7] ); + TRACE_OBJ( aafi, TimelineMobSlot, &__td ); - if ( rc < 0 ) { - error( "Failed to set unique filename with SourceMobID UID" ); - free( unique ); - return NULL; - } - audioEssence->unique_file_name = unique; + aafiAudioEssenceFile *audioEssenceFile = (aafiAudioEssenceFile*)aafi->ctx.current_audio_essence; - return unique; + audioEssenceFile->sourceMobSlotOrigin = *Origin; + audioEssenceFile->sourceMobSlotEditRate = edit_rate; + } + else { + TRACE_OBJ( aafi, TimelineMobSlot, &__td ); + } + } + else { + /* + * AAFClassID_MasterMob and AAFClassID_SourceMob are accessed directly from TimelineMobSlot > SourceClip + */ + TRACE_OBJ_NO_SUPPORT( aafi, TimelineMobSlot, &__td ); + return -1; } + return 0; +} - int index = 0; - foreachEssence( ae, aafi->Audio->Essences ) { - if ( ae->unique_file_name != NULL && wcscmp( ae->unique_file_name, unique ) == 0 ) { +static int parse_EventMobSlot( AAF_Iface *aafi, aafObject *EventMobSlot, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 0); + - if ( swprintf( unique+file_name_len, (unique_size-file_name_len), L"_%i", ++index ) < 0 ) { - error( "Failed to increment unique filename" ); - free( unique ); - return NULL; - } + aafRational_t *edit_rate = aaf_get_propertyValue( EventMobSlot, PID_EventMobSlot_EditRate, &AAFTypeID_Rational ); - ae = aafi->Audio->Essences; // check again - // debug( "%ls", unique ); - } + if ( !edit_rate ) { + TRACE_OBJ_ERROR( aafi, EventMobSlot, &__td, "Missing EventMobSlot::EditRate" ); + return -1; } - audioEssence->unique_file_name = unique; + TRACE_OBJ( aafi, EventMobSlot, &__td ); - // debug( "%ls", audioEssence->wunique_file_name ); + aafi->ctx.current_markers_edit_rate = edit_rate; - return unique; + return 0; } -static wchar_t * build_unique_videofilename( AAF_Iface *aafi, aafiVideoEssence *videoEssence ) +/* **************************************************************************** + * C o m p o n e n t + * **************************************************************************** + * + * Component (abs) + * | + * ,-----------. + * | | + * Transition Segment (abs) + * | + * |--> Sequence + * |--> Filler + * |--> TimeCode + * |--> OperationGroup + * `--> SourceReference (abs) + * | + * `--> SourceClip + */ + +static int parse_Component( AAF_Iface *aafi, aafObject *Component, td *__ptd ) { - /* TODO 1024 should be a macro ! */ + struct trace_dump __td; + __td_set(__td, __ptd, 0); - wchar_t *unique = calloc( sizeof(wchar_t), 1024 ); - size_t file_name_len = wcslen( videoEssence->file_name ); + if ( aafUIDCmp( Component->Class->ID, &AAFClassID_Transition ) ) { + parse_Transition( aafi, Component, &__td ); + } + else { + parse_Segment( aafi, Component, &__td ); + } + + return 0; +} - // debug( "%i", file_name_len ); - memcpy( unique, videoEssence->file_name, (file_name_len + 1) * sizeof(wchar_t) ); - // debug( "%ls", unique ); +static int parse_Transition( AAF_Iface *aafi, aafObject *Transition, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 1); - aafiVideoEssence *ve = NULL; + /* + * A Transition between a Filler and a SourceClip sets a Fade In. + * A Transition between a SourceClip and a Filler sets a Fade Out. + * A Transition between two SourceClips sets a Cross-Fade. + * + * Since the Transition applies to the elements that suround it in + * the Sequence, the OperationGroup::InputSegments is left unused. + */ - if ( 1 ) { + aafWeakRef_t *dataDefWeakRef = aaf_get_propertyValue( Transition, PID_Component_DataDefinition, &AAFTypeID_DataDefinitionWeakReference ); - size_t i = 0; + if ( !dataDefWeakRef ) { + TRACE_OBJ_ERROR( aafi, Transition, &__td, "Missing Component::DataDefinition." ); + return -1; + } - for ( ; i < file_name_len; i++ ) { + aafUID_t *DataDefinition = aaf_get_DataIdentificationByWeakRef( aafi->aafd, dataDefWeakRef ); - /* if char is out of the Basic Latin range */ + if ( !DataDefinition ) { + TRACE_OBJ_ERROR( aafi, Transition, &__td, "Could not retrieve DataDefinition" ); + return -1; + } - if ( unique[i] > 0xff ) { + if ( !aafUIDCmp( DataDefinition, &AAFDataDef_Sound ) && + !aafUIDCmp( DataDefinition, &AAFDataDef_LegacySound ) ) + { + TRACE_OBJ_ERROR( aafi, Transition, &__td, "Current implementation does not support video Transitions" ); + return -1; + } - // debug( "MobID : %ls", aaft_MobIDToText( videoEssence->sourceMobID ) ); - aafUID_t *uuid = &(videoEssence->sourceMobID->material); - swprintf( unique, 1024, L"%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", - uuid->Data1, - uuid->Data2, - uuid->Data3, - uuid->Data4[0], - uuid->Data4[1], - uuid->Data4[2], - uuid->Data4[3], - uuid->Data4[4], - uuid->Data4[5], - uuid->Data4[6], - uuid->Data4[7] ); - videoEssence->unique_file_name = unique; + int64_t *length = aaf_get_propertyValue( Transition, PID_Component_Length, &AAFTypeID_LengthType ); - return unique; - } - } + if ( !length ) { + TRACE_OBJ_ERROR( aafi, Transition, &__td, "Missing Component::Length" ); + return -1; } + aafObject * OpGroup = aaf_get_propertyValue( Transition, PID_Transition_OperationGroup, &AAFTypeID_OperationGroupStrongReference ); - int id = 0; - - foreachEssence( ve, aafi->Video->Essences ) { + if ( !OpGroup ) { + TRACE_OBJ_ERROR( aafi, Transition, &__td, "Missing Transition::OperationGroup" ); + return -1; + } - if ( ve->unique_file_name != NULL && wcscmp( ve->unique_file_name, unique ) == 0 ) { + aafPosition_t *cutPoint = aaf_get_propertyValue( Transition, PID_Transition_CutPoint, &AAFTypeID_PositionType ); - swprintf( unique+file_name_len, (1024-file_name_len), L"_%i", ++id ); - // debug( "%ls", unique ); - ve = aafi->Video->Essences; // check again - } + if ( !cutPoint ) { + /* not encountered though */ + debug( "Missing Transition::CutPoint : setting cut point to Transition::Length/2" ); } - videoEssence->unique_file_name = unique; - // debug( "%ls", videoEssence->wunique_file_name ); + uint32_t fadeType = 0; - return unique; -} + if ( Transition->prev != NULL && aafUIDCmp( Transition->prev->Class->ID, &AAFClassID_Filler ) ) { + fadeType |= AAFI_TRANS_FADE_IN; + } + else + if ( Transition->next != NULL && aafUIDCmp( Transition->next->Class->ID, &AAFClassID_Filler ) ) { + fadeType |= AAFI_TRANS_FADE_OUT; + } + else + if ( Transition->next != NULL && aafUIDCmp( Transition->next->Class->ID, &AAFClassID_Filler ) == 0 && + Transition->prev != NULL && aafUIDCmp( Transition->prev->Class->ID, &AAFClassID_Filler ) == 0 ) + { + fadeType |= AAFI_TRANS_XFADE; + } + else { + TRACE_OBJ_ERROR( aafi, Transition, &__td, "Could not guess if type is FadeIn, FadeOut or xFade" ); + return -1; + } + TRACE_OBJ( aafi, Transition, &__td ); -static aafObject * get_Object_Ancestor( AAF_Iface *aafi, aafObject *Obj, const aafUID_t *ClassID ) -{ - (void)aafi; + + aafiTransition *Trans = aafi_newTransition( aafi, aafi->ctx.current_track ); + + Trans->len = *length; + Trans->flags = fadeType; + Trans->cut_pt = (cutPoint) ? *cutPoint : (Trans->len/2); /* - * NOTE : AAFClassID_ContentStorage is the container of Mob and EssenceData, - * not of Identification, Dictionary and MetaDictionary. If needed, the func - * should work for them too thanks to Obj != NULL. + * OperationGroup *might* contain a Parameter (ParameterDef_Level) specifying + * the fade curve. However, this parameter is optional regarding AAF_EditProtocol + * and there is most likely no implementation that exports custom fade curves. + * Thus, we only retrieve ParameterDef_Level to possibly set interpolation, and we + * always set the fade as defined in AAF_EditProtocol, with only two points : + * + * « ParameterDef_Level (optional; default is a VaryingValue object + * with two control points: Value 0 at time 0, and value 1 at time 1) » */ - while ( Obj != NULL && !aafUIDCmp( Obj->Class->ID, &AAFClassID_ContentStorage ) ) { + if ( fadeType & AAFI_TRANS_FADE_IN || + fadeType & AAFI_TRANS_XFADE ) + { + Trans->value_a[0].numerator = 0; + Trans->value_a[0].denominator = 0; + Trans->value_a[1].numerator = 1; + Trans->value_a[1].denominator = 1; + } + else + if ( fadeType & AAFI_TRANS_FADE_OUT ) { + Trans->value_a[0].numerator = 1; + Trans->value_a[0].denominator = 1; + Trans->value_a[1].numerator = 0; + Trans->value_a[1].denominator = 0; + } - if ( aafUIDCmp( ClassID, Obj->Class->ID ) ) { - return Obj; - } - /* Works also with abstract class */ + aafi->ctx.current_transition = Trans; - if ( aafUIDCmp( ClassID, &AAFClassID_Mob ) && ( - aafUIDCmp( Obj->Class->ID, &AAFClassID_MasterMob ) || - aafUIDCmp( Obj->Class->ID, &AAFClassID_SourceMob ) || - aafUIDCmp( Obj->Class->ID, &AAFClassID_CompositionMob ) ) ) - { - return Obj; - } + parse_OperationGroup( aafi, OpGroup, &__td ); - if ( aafUIDCmp( ClassID, &AAFClassID_MobSlot ) && ( - aafUIDCmp( Obj->Class->ID, &AAFClassID_TimelineMobSlot ) || - aafUIDCmp( Obj->Class->ID, &AAFClassID_StaticMobSlot ) || - aafUIDCmp( Obj->Class->ID, &AAFClassID_EventMobSlot ) ) ) - { - return Obj; - } + aafi->ctx.current_transition = NULL; + aafi->ctx.current_track->current_pos -= *length; - Obj = Obj->Parent; - } - return NULL; + return 0; } -/* **************************************************************************** - * D i c t i o n a r y - * ****************************************************************************/ - -static aafUID_t * get_Component_DataDefinition( AAF_Iface *aafi, aafObject *Component ) +int parse_Segment( AAF_Iface *aafi, aafObject *Segment, td *__ptd ) { - aafWeakRef_t *weakRef = aaf_get_propertyValue( Component, PID_Component_DataDefinition, &AAFTypeID_DataDefinitionWeakReference ); + struct trace_dump __td; + __td_set(__td, __ptd, 0); + - if ( weakRef == NULL ) { - warning( "Missing Component::DataDefinition." ); - return NULL; + if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_Sequence ) ) { + return parse_Sequence( aafi, Segment, &__td ); + } + else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_SourceClip ) ) { + return parse_SourceClip( aafi, Segment, &__td ); + } + else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_OperationGroup ) ) { + return parse_OperationGroup( aafi, Segment, &__td ); } + else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_Filler ) ) { + return parse_Filler( aafi, Segment, &__td ); + } + else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_Selector ) ) { + return parse_Selector( aafi, Segment, &__td ); + } + else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_NestedScope ) ) { + return parse_NestedScope( aafi, Segment, &__td ); + } + else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_Timecode ) ) { + return parse_Timecode( aafi, Segment, &__td ); + } + else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_DescriptiveMarker ) ) { + return parse_DescriptiveMarker( aafi, Segment, &__td ); + } + else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_EssenceGroup ) ) { + /* + * Should provide support for multiple essences representing the same + * source material with different resolution, compression, codec, etc. + * + * TODO To be tested with Avid and rendered effects ? + */ - aafObject *DataDefinition = aaf_get_ObjectByWeakRef( aafi->aafd->DataDefinition, weakRef ); + __td.lv++; + TRACE_OBJ_NO_SUPPORT( aafi, Segment, &__td ); + __td.lv--; - if ( DataDefinition == NULL ) { - warning( "Could not retrieve WeakRef from Dictionary::DataDefinition." ); - return NULL; + return -1; } + else { + __td.lv++; + TRACE_OBJ_NO_SUPPORT( aafi, Segment, &__td ); + __td.lv--; - - aafUID_t *DataIdentification = aaf_get_propertyValue( DataDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID ); - - if ( DataIdentification == NULL ) { - warning( "Missing DataDefinition's DefinitionObject::Identification." ); - return NULL; + return -1; } - return DataIdentification; + return 0; } -// static aafUID_t * get_FileDescriptor_ContainerFormat( AAF_Iface *aafi, aafObject *FileDescriptor ) -// { -// aafWeakRef_t *ContainerDefWeakRef = aaf_get_propertyValue( FileDescriptor, PID_FileDescriptor_ContainerFormat, &AAFTypeID_ClassDefinitionWeakReference ); -// -// if ( ContainerDefWeakRef == NULL ) { -// warning( "Missing FileDescriptor::ContainerFormat." ); -// return NULL; -// } -// -// aafObject *ContainerDefinition = aaf_get_ObjectByWeakRef( aafi->aafd->ContainerDefinition, ContainerDefWeakRef ); -// -// if ( ContainerDefinition == NULL ) { -// warning( "Could not retrieve WeakRef from Dictionary::ContainerDefinitions." ); -// return NULL; -// } -// -// -// aafUID_t *ContainerIdentification = aaf_get_propertyValue( ContainerDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID ); -// -// if ( ContainerIdentification == NULL ) { -// warning( "Missing ContainerDefinition's DefinitionObject::Identification." ); -// return NULL; -// } -// -// -// return ContainerIdentification; -// } - - - - -static aafUID_t * get_OperationGroup_OperationIdentification( AAF_Iface *aafi, aafObject *OperationGroup ) +static int parse_Filler( AAF_Iface *aafi, aafObject *Filler, td *__ptd ) { - aafWeakRef_t *OperationDefWeakRef = aaf_get_propertyValue( OperationGroup, PID_OperationGroup_Operation, &AAFTypeID_OperationDefinitionWeakReference ); - - if ( OperationDefWeakRef == NULL ) { - error( "Missing OperationGroup::Operation." ); - return NULL; - } + struct trace_dump __td; + __td_set(__td, __ptd, 1); + __td.eob = 1; - aafObject *OperationDefinition = aaf_get_ObjectByWeakRef( aafi->aafd->OperationDefinition, OperationDefWeakRef ); + aafWeakRef_t *dataDefWeakRef = aaf_get_propertyValue( Filler, PID_Component_DataDefinition, &AAFTypeID_DataDefinitionWeakReference ); - if ( OperationDefinition == NULL ) { - error( "Could not retrieve OperationDefinition from dictionary." ); - return NULL; + if ( !dataDefWeakRef ) { + TRACE_OBJ_ERROR( aafi, Filler, &__td, "Missing Component::DataDefinition." ); + return -1; } + aafUID_t *DataDefinition = aaf_get_DataIdentificationByWeakRef( aafi->aafd, dataDefWeakRef ); - aafUID_t *OperationIdentification = aaf_get_propertyValue( OperationDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID ); - - if ( OperationIdentification == NULL ) { - error( "Missing DefinitionObject::Identification." ); - return NULL; + if ( !DataDefinition ) { + TRACE_OBJ_ERROR( aafi, Filler, &__td, "Could not retrieve DataDefinition" ); + return -1; } + /* + * This represents an empty space on the timeline, between two clips, + * which is Component::Length long. + * TODO: is realy parent mandatory a Sequence or Selector ? + */ - return OperationIdentification; -} - - - -/* TODO not parameter ? VaryingValue ? */ -static aafUID_t * get_Parameter_InterpolationIdentification( AAF_Iface *aafi, aafObject *Parameter ) -{ - aafWeakRef_t *InterpolationDefWeakRef = aaf_get_propertyValue( Parameter, PID_VaryingValue_Interpolation, &AAFTypeID_InterpolationDefinitionWeakReference ); + int64_t *length = aaf_get_propertyValue( Filler, PID_Component_Length, &AAFTypeID_LengthType ); - if ( InterpolationDefWeakRef == NULL ) { - error( "Missing Parameter::Interpolation." ); - return NULL; + if ( !length ) { + TRACE_OBJ_ERROR( aafi, Filler, &__td, "Missing Component::Length" ); + return -1; } - aafObject *InterpolationDefinition = aaf_get_ObjectByWeakRef( aafi->aafd->InterpolationDefinition, InterpolationDefWeakRef ); - - if ( InterpolationDefinition == NULL ) { - error( "Could not find InterpolationDefinition." ); - return NULL; + if ( aafUIDCmp( DataDefinition, &AAFDataDef_Sound ) || + aafUIDCmp( DataDefinition, &AAFDataDef_LegacySound ) ) + { + aafi->ctx.current_track->current_pos += *length; } - - - aafUID_t *InterpolationIdentification = aaf_get_propertyValue( InterpolationDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID ); - - if ( InterpolationIdentification == NULL ) { - error( "Missing Parameter DefinitionObject::Identification." ); - return NULL; + else + if ( aafUIDCmp( DataDefinition, &AAFDataDef_Picture ) || + aafUIDCmp( DataDefinition, &AAFDataDef_LegacyPicture ) ) + { + aafi->Video->Tracks->current_pos += *length; } - return InterpolationIdentification; + TRACE_OBJ( aafi, Filler, &__td ); + + return 0; } -static aafObject * get_EssenceData_By_MobID( AAF_Iface *aafi, aafMobID_t *MobID ) +static int parse_SourceClip( AAF_Iface *aafi, aafObject *SourceClip, td *__ptd ) { - aafMobID_t *DataMobID = NULL; - aafObject *EssenceData = NULL; + struct trace_dump __td; + __td_set(__td, __ptd, 1); - for ( EssenceData = aafi->aafd->EssenceData; EssenceData != NULL; EssenceData = EssenceData->next ) { - DataMobID = aaf_get_propertyValue( EssenceData, PID_EssenceData_MobID, &AAFTypeID_MobIDType ); + aafWeakRef_t *dataDefWeakRef = aaf_get_propertyValue( SourceClip, PID_Component_DataDefinition, &AAFTypeID_DataDefinitionWeakReference ); - if ( aafMobIDCmp( DataMobID, MobID ) ) - break; + if ( !dataDefWeakRef ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Missing Component::DataDefinition." ); + return -1; } - return EssenceData; -} + aafUID_t *DataDefinition = aaf_get_DataIdentificationByWeakRef( aafi->aafd, dataDefWeakRef ); + if ( !DataDefinition ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve DataDefinition" ); + return -1; + } -// /* TODO is this SourceMobID or SourceID (masterMobID) ??? */ -// static aafiAudioEssence * getAudioEssenceBySourceMobID( AAF_Iface *aafi, aafMobID_t *sourceMobID ) -// { -// aafiAudioEssence * audioEssence = NULL; -// -// -// for ( audioEssence = aafi->Audio->Essences; audioEssence != NULL; audioEssence = audioEssence->next ) { -// if ( aafMobIDCmp( audioEssence->masterMobID, sourceMobID ) ) -// break; -// } -// -// -// return audioEssence; -// } + aafObject *ParentMob = aaf_get_ObjectAncestor( SourceClip, &AAFClassID_Mob ); -// /* TODO is this SourceMobID or SourceID (masterMobID) ??? */ -// static aafiVideoEssence * getVideoEssenceBySourceMobID( AAF_Iface *aafi, aafMobID_t *sourceMobID ) -// { -// aafiVideoEssence * videoEssence = NULL; -// -// // debug( "%p", aafi->Video->tc ); -// debug( "%p", aafi->Video->Essences ); -// debug( "%ls", aaft_MobIDToText( sourceMobID ) ); -// -// -// for ( videoEssence = aafi->Video->Essences; videoEssence != NULL; videoEssence = videoEssence->next ) { -// if ( aafMobIDCmp( videoEssence->masterMobID, sourceMobID ) ) -// break; -// } -// -// -// return videoEssence; -// } + if ( !ParentMob ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve parent Mob" ); + return -1; + } + aafMobID_t *parentMobID = aaf_get_propertyValue( ParentMob, PID_Mob_MobID, &AAFTypeID_MobIDType ); + if ( !parentMobID ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Missing parent Mob::MobID" ); + return -1; + } + aafUID_t *parentMobUsageCode = aaf_get_propertyValue( ParentMob, PID_Mob_UsageCode, &AAFTypeID_UsageType ); + if ( !parentMobUsageCode ) { + debug( "Missing parent Mob Mob::UsageCode" ); + } + aafMobID_t *sourceID = aaf_get_propertyValue( SourceClip, PID_SourceReference_SourceID, &AAFTypeID_MobIDType ); + uint32_t *SourceMobSlotID = aaf_get_propertyValue( SourceClip, PID_SourceReference_SourceMobSlotID, &AAFTypeID_UInt32 ); + if ( !SourceMobSlotID ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Missing SourceReference::SourceMobSlotID" ); + return -1; + } + /* + * TODO: handle SourceReference::ChannelIDs and SourceReference::MonoSourceSlotIDs + * (Multi-channels) + */ + aafObject *targetMob = NULL; + aafObject *targetMobSlot = NULL; + if ( sourceID == NULL || aafMobIDCmp( sourceID, &AAFMOBID_NULL ) ) { + /* + * p.49 : To create a SourceReference that refers to a MobSlot within + * the same Mob as the SourceReference, omit the SourceID property. + * + * [SourceID] Identifies the Mob being referenced. If the property has a + * value 0, it means that the Mob owning the SourceReference describes + * the original source. + * + * TODO: in that case, is MobSlots NULL ? + */ + // sourceID = parentMobID; + // targetMob = ParentMob; -/* **************************************************************************** - * E s s e n c e D e s c r i p t o r - * **************************************************************************** - * - * EssenceDescriptor (abs) - * | - * |--> FileDescriptor (abs) - * | | - * | |--> WAVEDescriptor - * | |--> AIFCDescriptor - * | |--> SoundDescriptor - * | | | - * | | `--> PCMDescriptor - * | | - * | `--> DigitalImageDescriptor (abs) - * | | - * | `--> CDCIDescriptor - * | - * | - * |--> PhysicalDescriptor - * `--> TapeDescriptor - */ - -static int parse_EssenceDescriptor( AAF_Iface *aafi, aafObject *EssenceDesc, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 0); - - - if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_PCMDescriptor ) ) { - parse_PCMDescriptor( aafi, EssenceDesc, &__td ); - } - else if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_WAVEDescriptor ) ) { - parse_WAVEDescriptor( aafi, EssenceDesc, &__td ); - } - else if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_AIFCDescriptor ) ) { - parse_AIFCDescriptor( aafi, EssenceDesc, &__td ); - } - else if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_SoundDescriptor ) ) { - - /* Compressed Audio (MP3, AAC ?). Not encountered yet */ - - __td.lv++; - DUMP_OBJ_NO_SUPPORT( aafi, EssenceDesc, &__td ); - __td.lv--; - } - else if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_AES3PCMDescriptor ) ) { - - /* Not described in specs, not encountered yet. */ - - __td.lv++; - DUMP_OBJ_NO_SUPPORT( aafi, EssenceDesc, &__td ); - __td.lv--; - } - else if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_MultipleDescriptor ) ) { - - /* - * A MultipleDescriptor contains a vector of FileDescriptor objects and is - * used when the file source consists of multiple tracks of essence (e.g MXF). - * Each essence track is described by a MobSlots object in the SourceMob and a - * FileDescriptor object. The FileDescriptor is linked to the MobSlot by - * setting the FileDescriptor::LinkedSlotID property equal to the - * MobSlot::SlotID property. - * - * -> test.aaf - */ - - __td.lv++; - DUMP_OBJ_NO_SUPPORT( aafi, EssenceDesc, &__td ); - __td.lv--; - - } - else if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_CDCIDescriptor ) ) { - parse_CDCIDescriptor( aafi, EssenceDesc, &__td ); - } - else { - __td.lv++; - DUMP_OBJ_NO_SUPPORT( aafi, EssenceDesc, &__td ); - __td.lv--; - } - - - /* - * Locators are a property of EssenceDescriptor. The property holds a vector of - * Locators object, that should provide information to help find a file that - * contains the essence (WAV, MXF, etc.) or to help find the physical media. - * - * A Locator can either be a NetworkLocator or a TextLocator. - * - * A NetworkLocator holds a URLString property : - * - * p.41 : Absolute Uniform Resource Locator (URL) complying with RFC 1738 or relative - * Uniform Resource Identifier (URI) complying with RFC 2396 for file containing - * the essence. If it is a relative URI, the base URI is determined from the URI - * of the AAF file itself. - * Informative note: A valid URL or URI uses a constrained character set and uses - * the / character as the path separator. - */ - - aafObject *Locator = NULL; - aafObject *Locators = aaf_get_propertyValue( EssenceDesc, PID_EssenceDescriptor_Locator, &AAFTypeID_LocatorStrongReferenceVector ); /* opt */ - - __td.lv++; - int i = 0; - - aaf_foreach_ObjectInSet( &Locator, Locators, NULL ) { - /* TODO retrieve all locators, then when searching file, try all parsed locators. */ - __td.ll[__td.lv] = (Locators->Header->_entryCount > 1) ? (Locators->Header->_entryCount - i++) : 0; - parse_Locator( aafi, Locator, &__td ); - } - - - return 0; -} - - - -static int parse_DigitalImageDescriptor( AAF_Iface *aafi, aafObject *DIDescriptor, td *__ptd ) -{ - struct trace_dump __td; - __td_set(__td, __ptd, 0); - - - /* TODO parse and save content to videoEssence */ - - - aafiVideoEssence *videoEssence = aafi->ctx.current_video_essence;//(aafiVideoEssence*)aafi->ctx.current_essence; - - if ( videoEssence == NULL ) { - DUMP_OBJ_ERROR( aafi, DIDescriptor, &__td, "aafi->ctx.current_video_essence not set" ); - return -1; - } - - /* - * « Informative note: In the case of picture essence, the Sample Rate is usually the frame rate. The value should be - * numerically exact, for example {25,1} or {30000, 1001}. » - * - * « Informative note: Care should be taken if a sample rate of {2997,100} is encountered, since this may have been intended - * as a (mistaken) approximation to the exact value. » - */ - - aafRational_t *framerate = aaf_get_propertyValue( DIDescriptor, PID_FileDescriptor_SampleRate, &AAFTypeID_Rational ); - - if ( framerate == NULL ) { /* REQ */ - DUMP_OBJ_ERROR( aafi, DIDescriptor, &__td, "Missing PID_FileDescriptor_SampleRate (framerate)" ); - return -1; - } - - videoEssence->framerate = framerate; - - debug("Video framerate : %i/%i", framerate->numerator, framerate->denominator ); - - - /* - * All mandatory properties below are treated as optional, because we assume that - * video will be an external file so we are not using those, and because some AAF - * implementations does not even set those mandatory properties (eg. Davinci Resolve). - * - * TODO: parse PID_FileDescriptor_Length ? - */ - - - uint32_t *storedHeight = aaf_get_propertyValue( DIDescriptor, PID_DigitalImageDescriptor_StoredHeight, &AAFTypeID_UInt32 ); - - if ( storedHeight == NULL ) { /* REQ */ - DUMP_OBJ_WARNING( aafi, DIDescriptor, &__td, "Missing PID_DigitalImageDescriptor_StoredHeight" ); - } - - // debug( "storedHeight : %u", *storedHeight ); - - - - uint32_t *storedWidth = aaf_get_propertyValue( DIDescriptor, PID_DigitalImageDescriptor_StoredWidth, &AAFTypeID_UInt32 ); - - if ( storedWidth == NULL ) { /* REQ */ - DUMP_OBJ_WARNING( aafi, DIDescriptor, &__td, "Missing PID_DigitalImageDescriptor_StoredWidth" ); - } - - // debug( "storedWidth : %u", *storedWidth ); - - - - uint32_t *displayHeight = aaf_get_propertyValue( DIDescriptor, PID_DigitalImageDescriptor_DisplayHeight, &AAFTypeID_UInt32 ); - - if ( displayHeight == NULL ) { - DUMP_OBJ_WARNING( aafi, DIDescriptor, &__td, "Missing PID_DigitalImageDescriptor_DisplayHeight" ); - } - - // debug( "displayHeight : %u", *displayHeight ); - - - - uint32_t *displayWidth = aaf_get_propertyValue( DIDescriptor, PID_DigitalImageDescriptor_DisplayWidth, &AAFTypeID_UInt32 ); - - if ( displayWidth == NULL ) { - DUMP_OBJ_WARNING( aafi, DIDescriptor, &__td, "Missing PID_DigitalImageDescriptor_DisplayWidth" ); - } - - // debug( "displayWidth : %u", *displayWidth ); - - - - aafRational_t *imageAspectRatio = aaf_get_propertyValue( DIDescriptor, PID_DigitalImageDescriptor_ImageAspectRatio, &AAFTypeID_Rational ); - - if ( imageAspectRatio == NULL ) { /* REQ */ - DUMP_OBJ_WARNING( aafi, DIDescriptor, &__td, "Missing PID_DigitalImageDescriptor_ImageAspectRatio" ); - } - - // debug( "imageAspectRatio : %i/%i", imageAspectRatio->numerator, imageAspectRatio->denominator ); - - - - return 0; -} - - - -static int parse_CDCIDescriptor( AAF_Iface *aafi, aafObject *CDCIDescriptor, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 1); - - if ( !aaf_get_property( CDCIDescriptor, PID_EssenceDescriptor_Locator ) ) - __td.eob = 1; - - - /* TODO parse CDCI class */ - - - - int rc = parse_DigitalImageDescriptor( aafi, CDCIDescriptor, __ptd ); - - if ( !rc ) - DUMP_OBJ( aafi, CDCIDescriptor, &__td ); - - - return rc; -} - - - -static int parse_PCMDescriptor( AAF_Iface *aafi, aafObject *PCMDescriptor, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 1); - - if ( !aaf_get_property( PCMDescriptor, PID_EssenceDescriptor_Locator ) ) - __td.eob = 1; - - - - aafiAudioEssence *audioEssence = (aafiAudioEssence*)aafi->ctx.current_essence; - - if ( audioEssence == NULL ) { - DUMP_OBJ_ERROR( aafi, PCMDescriptor, &__td, "aafi->ctx.current_essence not set" ); - return -1; - } - - - audioEssence->type = AAFI_ESSENCE_TYPE_PCM; - - - - /* Duration of the essence in sample units (not edit units !) */ - aafPosition_t *length = aaf_get_propertyValue( PCMDescriptor, PID_FileDescriptor_Length, &AAFTypeID_PositionType ); - - if ( length == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, PCMDescriptor, &__td, "Missing PID_FileDescriptor_Length" ); - return -1; - } - - audioEssence->length = *length; - - - - uint32_t *channels = aaf_get_propertyValue( PCMDescriptor, PID_SoundDescriptor_Channels, &AAFTypeID_UInt32 ); - - if ( channels == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, PCMDescriptor, &__td, "Missing PID_SoundDescriptor_Channels" ); - return -1; - } - - audioEssence->channels = *channels; - - - - aafRational_t *samplerate = aaf_get_propertyValue( PCMDescriptor, PID_FileDescriptor_SampleRate, &AAFTypeID_Rational ); - - if ( samplerate == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, PCMDescriptor, &__td, "Missing PID_FileDescriptor_SampleRate" ); - return -1; - } - - if ( samplerate->denominator != 1 ) { - DUMP_OBJ_ERROR( aafi, PCMDescriptor, &__td, "PID_FileDescriptor_SampleRate should be integer but is %i/%i", samplerate->numerator, samplerate->denominator ); - return -1; - } - - audioEssence->samplerate = samplerate->numerator; - audioEssence->samplerateRational->numerator = samplerate->numerator; - audioEssence->samplerateRational->denominator = samplerate->denominator; - - - - uint32_t *samplesize = aaf_get_propertyValue( PCMDescriptor, PID_SoundDescriptor_QuantizationBits, &AAFTypeID_UInt32 ); // uint32_t in AAF std - - if ( samplesize == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, PCMDescriptor, &__td, "Missing PID_SoundDescriptor_QuantizationBits" ); - return -1; - } - - if ( *samplesize >= (1<<15) ) { - DUMP_OBJ_ERROR( aafi, PCMDescriptor, &__td, "PID_SoundDescriptor_QuantizationBits value error : %u", *samplesize ); - return -1; - } - - audioEssence->samplesize = (int16_t)*samplesize; - - if ( aafi->Audio->samplesize >= 0 ) { - /* Set global AAF SampleSize, if it equals preceding. Otherwise set to -1 */ - aafi->Audio->samplesize = ( aafi->Audio->samplesize == 0 || (uint16_t)aafi->Audio->samplesize == audioEssence->samplesize ) ? audioEssence->samplesize : -1; - } - - - /* TODO parse the rest of the class */ - - DUMP_OBJ( aafi, PCMDescriptor, &__td ); - - - return 0; -} - - - -static int parse_WAVEDescriptor( AAF_Iface *aafi, aafObject *WAVEDescriptor, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 1); - - if ( !aaf_get_property( WAVEDescriptor, PID_EssenceDescriptor_Locator ) ) - __td.eob = 1; - - - - aafiAudioEssence *audioEssence = (aafiAudioEssence*)aafi->ctx.current_essence; - - if ( audioEssence == NULL ) { - DUMP_OBJ_ERROR( aafi, WAVEDescriptor, &__td, "aafi->ctx.current_essence not set" ); - return -1; - } - - - audioEssence->type = AAFI_ESSENCE_TYPE_WAVE; - - - - aafProperty *summary = aaf_get_property( WAVEDescriptor, PID_WAVEDescriptor_Summary ); - - if ( summary == NULL ) { - DUMP_OBJ_ERROR( aafi, WAVEDescriptor, &__td, "Missing PID_WAVEDescriptor_Summary" ); - return -1; - } - - audioEssence->summary = summary; - - /* - * NOTE : Summary is parsed later in "post-processing" aafi_retrieveData(), - * to be sure clips and essences are linked, so we are able to fallback on - * essence stream in case summary does not contain the full header part. - * - * TODO parse it here - */ - - DUMP_OBJ( aafi, WAVEDescriptor, &__td ); - - - return 0; -} - - - -static int parse_AIFCDescriptor( AAF_Iface *aafi, aafObject *AIFCDescriptor, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 1); - - if ( !aaf_get_property( AIFCDescriptor, PID_EssenceDescriptor_Locator ) ) - __td.eob = 1; - - - - aafiAudioEssence *audioEssence = (aafiAudioEssence*)aafi->ctx.current_essence; - - if ( audioEssence == NULL ) { - DUMP_OBJ_ERROR( aafi, AIFCDescriptor, &__td, "aafi->ctx.current_essence not set" ); - return -1; - } - - - audioEssence->type = AAFI_ESSENCE_TYPE_AIFC; - - - - aafProperty *summary = aaf_get_property( AIFCDescriptor, PID_AIFCDescriptor_Summary ); - - if ( summary == NULL ) { - DUMP_OBJ_ERROR( aafi, AIFCDescriptor, &__td, "Missing PID_AIFCDescriptor_Summary" ); - return -1; - } - - audioEssence->summary = summary; - - - /* - * NOTE : Summary is parsed later in "post-processing" aafi_retrieveData(), - * to be sure clips and essences are linked, so we are able to fallback on - * essence stream in case summary does not contain the full header part. - */ - - DUMP_OBJ( aafi, AIFCDescriptor, &__td ); - - - return 0; -} - - - -/* - * Locator (abs) - * | - * ,---------------. - * | | - * NetworkLocator TextLocator - */ - -static int parse_Locator( AAF_Iface *aafi, aafObject *Locator, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 0); - - - if ( aafUIDCmp( Locator->Class->ID, &AAFClassID_NetworkLocator ) ) { - parse_NetworkLocator( aafi, Locator, &__td ); - } - else if ( aafUIDCmp( Locator->Class->ID, &AAFClassID_TextLocator ) ) { - - /* - * A TextLocator object provides information to the user to help locate the file - * containing the essence or to locate the physical media. The TextLocator is not - * intended for applications to use without user intervention. - * - * TODO what to do with those ??? - * never encountered anyway.. - */ - - __td.eob = 1; - __td.lv++; - DUMP_OBJ_NO_SUPPORT( aafi, Locator, &__td ); - - // wchar_t *name = aaf_get_propertyValue( Locator, PID_TextLocator_Name, &AAFTypeID_String ); - // warning( "Got an AAFClassID_TextLocator : \"%ls\"", name ); - // free( name ); - } - else { - __td.eob = 1; - __td.lv++; - DUMP_OBJ_NO_SUPPORT( aafi, Locator, &__td ); - } - - - return 0; -} - - - -static int parse_NetworkLocator( AAF_Iface *aafi, aafObject *NetworkLocator, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 1); - __td.eob = 1; - - - /* - * This holds an URI pointing to the essence file, when it is not embedded. - * However, sometimes it holds an URI to the AAF file itself when essence is - * embedded so it is not a valid way to test if essence is embedded or not. - */ - - wchar_t *original_file_path = aaf_get_propertyValue( NetworkLocator, PID_NetworkLocator_URLString, &AAFTypeID_String ); - - if ( original_file_path == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, NetworkLocator, &__td, "Missing PID_NetworkLocator_URLString" ); - return -1; - } - - - /* TODO find a better way to check if we're parsing audio */ - - if ( aafi->ctx.current_essence ) { - aafi->ctx.current_essence->original_file_path = original_file_path; - } - else if ( aafi->ctx.current_video_essence ) { - aafi->ctx.current_video_essence->original_file_path = original_file_path; - } - else { - DUMP_OBJ_ERROR( aafi, NetworkLocator, &__td, "aafi->ctx.current_essence AND aafi->ctx.current_video_essence not set" ); - return -1; - } - - DUMP_OBJ_INFO( aafi, NetworkLocator, &__td, ": %ls", original_file_path ); - - return 0; -} - - - -static int parse_EssenceData( AAF_Iface *aafi, aafObject *EssenceData, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 1); - __td.eob = 1; - - - - aafiAudioEssence *audioEssence = (aafiAudioEssence*)aafi->ctx.current_essence; - - if ( audioEssence == NULL ) { - DUMP_OBJ_ERROR( aafi, EssenceData, &__td, "aafi->ctx.current_essence not set" ); - return -1; - } - - /* - * The EssenceData::Data property has the stored form SF_DATA_STREAM, so - * it holds the name of the Data stream, which should be located at - * /Path/To/EssenceData/DataStream - */ - - wchar_t *StreamName = aaf_get_propertyValue( EssenceData, PID_EssenceData_Data, &AAFTypeID_String ); - - if ( StreamName == NULL ) { - DUMP_OBJ_ERROR( aafi, EssenceData, &__td, "Missing PID_EssenceData_Data" ); - return -1; - } - - - - wchar_t DataPath[CFB_PATH_NAME_SZ]; - memset( DataPath, 0x00, sizeof(DataPath) ); - - wchar_t *path = aaf_get_ObjectPath( EssenceData ); - - swprintf( DataPath, CFB_PATH_NAME_SZ, L"%" WPRIws L"/%" WPRIws, path, StreamName ); - - free( StreamName ); - - - - cfbNode *DataNode = cfb_getNodeByPath( aafi->aafd->cfbd, DataPath, 0 ); - - if ( DataNode == NULL ) { - DUMP_OBJ_ERROR( aafi, EssenceData, &__td, "Could not retrieve Data stream node %ls", DataPath ); - return -1; - } - - audioEssence->node = DataNode; - - audioEssence->is_embedded = 1; /* TODO to be set elsewhere ? */ - - - - /* disable raw data byte length, because we want it to be the exact audio length in samples */ - - // uint64_t dataLen = cfb_getNodeStreamLen( aafi->aafd->cfbd, DataNode ); - // - // if ( dataLen == 0 ) { - // DUMP_OBJ_WARNING( aafi, EssenceData, &__td, "Got 0 Bytes Data stream length" ); - // return -1; - // } - // else { - // DUMP_OBJ( aafi, EssenceData, &__td ); - // } - // - // /* NOTE Might be tweaked by aafi_parse_audio_summary() */ - // audioEssence->length = dataLen; - - - return 0; -} - - - -/* **************************************************************************** - * C o m p o n e n t - * **************************************************************************** - * - * Component (abs) - * | - * ,-----------. - * | | - * Transition Segment (abs) - * | - * |--> Sequence - * |--> Filler - * |--> TimeCode - * |--> OperationGroup - * `--> SourceReference (abs) - * | - * `--> SourceClip - */ - -static int parse_Component( AAF_Iface *aafi, aafObject *Component, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 0); - - - - if ( aafUIDCmp( Component->Class->ID, &AAFClassID_Transition ) ) { - - /* - * A Transition between a Filler and a SourceClip sets a Fade In. - * A Transition between a SourceClip and a Filler sets a Fade Out. - * A Transition between two SourceClips sets a Cross-Fade. - * - * Since the Transition applies to the elements that suround it in - * the Sequence, the OperationGroup::InputSegments is then left unused. - */ - - parse_Transition( aafi, Component, &__td ); - } - else { - aafi_parse_Segment( aafi, Component, &__td ); - } - - - return 0; -} - - - -static int parse_Transition( AAF_Iface *aafi, aafObject *Transition, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 1); - - - - aafUID_t *DataDefinition = get_Component_DataDefinition( aafi, Transition ); - - if ( DataDefinition == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, Transition, &__td, "Could not retrieve DataDefinition" ); - return -1; - } - - if ( !aafUIDCmp( DataDefinition, &AAFDataDef_Sound ) && - !aafUIDCmp( DataDefinition, &AAFDataDef_LegacySound ) ) - { - DUMP_OBJ_ERROR( aafi, Transition, &__td, "Current implementation only supports Transition inside Audio Tracks" ); - return -1; - } - - - - int64_t *length = aaf_get_propertyValue( Transition, PID_Component_Length, &AAFTypeID_LengthType ); - - if ( length == NULL ) { - DUMP_OBJ_ERROR( aafi, Transition, &__td, "Missing PID_Component_Length" ); - return -1; - } - - - int flags = 0; - - if ( Transition->prev != NULL && aafUIDCmp( Transition->prev->Class->ID, &AAFClassID_Filler ) ) { - flags |= AAFI_TRANS_FADE_IN; - } - else - if ( Transition->next != NULL && aafUIDCmp( Transition->next->Class->ID, &AAFClassID_Filler ) ) { - flags |= AAFI_TRANS_FADE_OUT; - } - else - if ( Transition->next != NULL && aafUIDCmp( Transition->next->Class->ID, &AAFClassID_Filler ) == 0 && - Transition->prev != NULL && aafUIDCmp( Transition->prev->Class->ID, &AAFClassID_Filler ) == 0 ) - { - flags |= AAFI_TRANS_XFADE; - } - else { - DUMP_OBJ_ERROR( aafi, Transition, &__td, "Could not guess if type is FadeIn, FadeOut or xFade" ); - return -1; - } - - - - - aafiTimelineItem *Item = aafi_newTimelineItem( aafi, aafi->ctx.current_track, AAFI_TRANS ); - - aafiTransition *Trans = Item->data;//(aafiTransition*)&Item->data; - - - - Trans->len = *length; - Trans->flags = flags; - - - int missing_cutpt = 0; - - aafPosition_t *cut_point = aaf_get_propertyValue( Transition, PID_Transition_CutPoint, &AAFTypeID_PositionType ); - - if ( cut_point == NULL ) { /* req */ - // DUMP_OBJ_WARNING( aafi, Transition, &__td, "Missing PID_Transition_CutPoint : Setting to Trans->len/2" ); - missing_cutpt = 1; - Trans->cut_pt = Trans->len/2; // set default cutpoint to the middle of transition - } - else { - Trans->cut_pt = *cut_point; - } - - - aafObject * OpGroup = aaf_get_propertyValue( Transition, PID_Transition_OperationGroup, &AAFTypeID_OperationGroupStrongReference ); - - if ( OpGroup != NULL ) { /* req */ - - if ( missing_cutpt ) { - DUMP_OBJ_WARNING( aafi, Transition, &__td, "Missing PID_Transition_CutPoint : Setting to Trans->len/2" ); - } else { - DUMP_OBJ( aafi, Transition, &__td ); - } - - /* - * Don't handle parse_OperationGroup() return code, since it should - * always fallback to default in case of failure. - */ - - aafi->ctx.current_transition = Trans; - parse_OperationGroup( aafi, OpGroup, &__td ); - aafi->ctx.current_transition = NULL; - } - else { - /* Setting fade to default */ - - __td.eob = 1; - - if ( missing_cutpt ) { - DUMP_OBJ_WARNING( aafi, Transition, &__td, "Missing PID_Transition_CutPoint AND PID_Transition_OperationGroup : Setting to Trans->len/2; Linear" ); - } else { - DUMP_OBJ_WARNING( aafi, Transition, &__td, "Missing PID_Transition_OperationGroup : Setting to Linear interpolation" ); - } - - Trans->flags |= (AAFI_INTERPOL_LINEAR | AAFI_TRANS_SINGLE_CURVE); - - Trans->time_a = calloc( 2, sizeof(aafRational_t) ); - Trans->value_a = calloc( 2, sizeof(aafRational_t) ); - - Trans->time_a[0].numerator = 0; - Trans->time_a[0].denominator = 0; - Trans->time_a[1].numerator = 1; - Trans->time_a[1].denominator = 1; - - if ( Trans->flags & AAFI_TRANS_FADE_IN || - Trans->flags & AAFI_TRANS_XFADE ) - { - Trans->value_a[0].numerator = 0; - Trans->value_a[0].denominator = 0; - Trans->value_a[1].numerator = 1; - Trans->value_a[1].denominator = 1; - } - else if ( Trans->flags & AAFI_TRANS_FADE_OUT ) { - Trans->value_a[0].numerator = 1; - Trans->value_a[0].denominator = 1; - Trans->value_a[1].numerator = 0; - Trans->value_a[1].denominator = 0; - } - } - - - aafi->ctx.current_track->current_pos -= *length; - - - return 0; -} - - - -static int parse_NestedScope( AAF_Iface *aafi, aafObject *NestedScope, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 1); - - - - aafObject *Slot = NULL; - aafObject *Slots = aaf_get_propertyValue( NestedScope, PID_NestedScope_Slots, &AAFUID_NULL ); - - if ( Slots == NULL ) { - DUMP_OBJ_ERROR( aafi, NestedScope, &__td, "Missing PID_NestedScope_Slots" ); - return -1; - } - - - DUMP_OBJ( aafi, NestedScope, &__td ); - - - int i = 0; - - aaf_foreach_ObjectInSet( &Slot, Slots, NULL ) { - __td.ll[__td.lv] = (Slots->Header->_entryCount > 1) ? (Slots->Header->_entryCount - i++) : 0;//(MobSlot->next) ? 1 : 0; - aafi_parse_Segment( aafi, Slot, &__td ); - } - - /* TODO should we take aafi_parse_Segment() return code into account ? */ - - return 0; -} - - - -int aafi_parse_Segment( AAF_Iface *aafi, aafObject *Segment, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 0); - - - - if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_Sequence ) ) { - return parse_Sequence( aafi, Segment, &__td ); - } - else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_SourceClip ) ) { - return parse_SourceClip( aafi, Segment, &__td ); - } - else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_OperationGroup ) ) { - return parse_OperationGroup( aafi, Segment, &__td ); - } - else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_Filler ) ) { - return parse_Filler( aafi, Segment, &__td ); - } - else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_Selector ) ) { - return parse_Selector( aafi, Segment, &__td ); - } - else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_NestedScope ) ) { - return parse_NestedScope( aafi, Segment, &__td ); - } - else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_Timecode ) ) { - - /* - * TODO can contain sequence ? other Timecode SMPTE .. - */ - - return parse_Timecode( aafi, Segment, &__td ); - } - else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_DescriptiveMarker ) ) { - - if ( resolve_AAF( aafi ) ) { - resolve_parse_aafObject_DescriptiveMarker( aafi, Segment, &__td ); - } - else { - __td.lv++; - DUMP_OBJ_NO_SUPPORT( aafi, Segment, &__td ); - return -1; - } - } - else if ( aafUIDCmp( Segment->Class->ID, &AAFClassID_EssenceGroup ) ) { - - /* - * Should provide support for multiple essences representing the same - * source material with different resolution, compression, codec, etc. - * - * TODO To be tested with Avid and rendered effects. - */ - - __td.lv++; - DUMP_OBJ_NO_SUPPORT( aafi, Segment, &__td ); - return -1; + debug( "SourceReference::SourceID is missing or NULL" ); } else { - __td.lv++; - DUMP_OBJ_NO_SUPPORT( aafi, Segment, &__td ); - } - - - return 0; -} - - - -static int parse_Filler( AAF_Iface *aafi, aafObject *Filler, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 1); - - __td.eob = 1; - - - - aafUID_t *DataDefinition = get_Component_DataDefinition( aafi, Filler ); - - if ( DataDefinition == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, Filler, &__td, "Could not retrieve DataDefinition" ); - return -1; - } - - - - - if ( aafUIDCmp( Filler->Parent->Class->ID, &AAFClassID_TimelineMobSlot ) ) { - /* - * Just an empty track, do nothing. - */ - } - else - if ( aafUIDCmp( Filler->Parent->Class->ID, &AAFClassID_Sequence ) || - aafUIDCmp( Filler->Parent->Class->ID, &AAFClassID_Selector ) ) - { - /* - * This represents an empty space on the timeline, between two clips - * which is Component::Length long. - */ - - int64_t *length = aaf_get_propertyValue( Filler, PID_Component_Length, &AAFTypeID_LengthType ); + targetMob = aaf_get_MobByID( aafi->aafd->Mobs, sourceID ); - if ( length == NULL ) { /* probably req for Filler */ - DUMP_OBJ_ERROR( aafi, Filler, &__td, "Missing PID_Component_Length" ); + if ( !targetMob ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve target Mob by ID : %s", aaft_MobIDToText(sourceID) ); return -1; } + aafObject *targetMobSlots = aaf_get_propertyValue( targetMob, PID_Mob_Slots, &AAFTypeID_MobSlotStrongReferenceVector ); - if ( aafUIDCmp( DataDefinition, &AAFDataDef_Sound ) || - aafUIDCmp( DataDefinition, &AAFDataDef_LegacySound ) ) - { - aafi->ctx.current_track->current_pos += *length; - } - else - if ( aafUIDCmp( DataDefinition, &AAFDataDef_Picture ) || - aafUIDCmp( DataDefinition, &AAFDataDef_LegacyPicture ) ) - { - aafi->Video->Tracks->current_pos += *length; + if ( !targetMobSlots ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Missing target Mob::Slots" ); + return -1; } - } - else { - DUMP_OBJ_NO_SUPPORT( aafi, Filler, &__td ); - return -1; - } - - - DUMP_OBJ( aafi, Filler, &__td ); - - - return 0; -} - - - -static int parse_Sequence( AAF_Iface *aafi, aafObject *Sequence, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 1); - - - - aafObject *Component = NULL; - aafObject *Components = aaf_get_propertyValue( Sequence, PID_Sequence_Components, &AAFTypeID_ComponentStrongReferenceVector ); - - if ( Components == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, Sequence, &__td, "Missing PID_Sequence_Components" ); - return -1; - } - - - DUMP_OBJ( aafi, Sequence, &__td ); - - - int i = 0; - - aaf_foreach_ObjectInSet( &Component, Components, NULL ) { - __td.ll[__td.lv] = (Components->Header->_entryCount > 1) ? (Components->Header->_entryCount - i++) : 0;//(MobSlot->next) ? 1 : 0; - parse_Component( aafi, Component, &__td ); - } - - - return 0; -} - - - -static int parse_Timecode( AAF_Iface *aafi, aafObject *Timecode, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 1); - - __td.eob = 1; - - - - aafPosition_t *tc_start = aaf_get_propertyValue( Timecode, PID_Timecode_Start, &AAFTypeID_PositionType ); - - if ( tc_start == NULL ) { - DUMP_OBJ_ERROR( aafi, Timecode, &__td, "Missing PID_Timecode_Start" ); - return -1; - } - - - uint16_t *tc_fps = aaf_get_propertyValue( Timecode, PID_Timecode_FPS, &AAFTypeID_UInt16 ); - - if ( tc_fps == NULL ) { - DUMP_OBJ_ERROR( aafi, Timecode, &__td, "Missing PID_Timecode_FPS" ); - return -1; - } - - - uint8_t *tc_drop = aaf_get_propertyValue( Timecode, PID_Timecode_Drop, &AAFTypeID_UInt8 ); - - if ( tc_drop == NULL ) { - DUMP_OBJ_ERROR( aafi, Timecode, &__td, "Missing PID_Timecode_Drop" ); - return -1; - } - - - /* TODO this should be retrieved directly from TimelineMobSlot */ - - aafObject *ParentMobSlot = get_Object_Ancestor( aafi, Timecode, &AAFClassID_MobSlot ); - - if ( ParentMobSlot == NULL ) { - DUMP_OBJ_ERROR( aafi, Timecode, &__td, "Could not retrieve parent MobSlot" ); - return -1; - } - - aafRational_t *tc_edit_rate = aaf_get_propertyValue( ParentMobSlot, PID_TimelineMobSlot_EditRate, &AAFTypeID_Rational ); - - if ( tc_edit_rate == NULL ) { - DUMP_OBJ_ERROR( aafi, Timecode, &__td, "Missing parent MobSlot PID_TimelineMobSlot_EditRate" ); - return -1; - } - - - if ( aafi->Timecode ) { - DUMP_OBJ_WARNING( aafi, Timecode, &__td, "Timecode was already set, ignoring (%lu, %u fps)", *tc_start, *tc_fps ); - return -1; - } - /* TODO allocate in specific function */ - - aafiTimecode *tc = calloc( sizeof(aafiTimecode), sizeof(unsigned char) ); - - if ( tc == NULL ) { - DUMP_OBJ_ERROR( aafi, Timecode, &__td, "calloc() : %s", strerror( errno ) ); - return -1; - } - - tc->start = *tc_start; - tc->fps = *tc_fps; - tc->drop = *tc_drop; - tc->edit_rate = tc_edit_rate; - - aafi->Timecode = tc; - - - DUMP_OBJ( aafi, Timecode, &__td ); - - - return 0; -} - - - -static int parse_OperationGroup( AAF_Iface *aafi, aafObject *OpGroup, td *__ptd ) -{ - - struct trace_dump __td; - __td_set(__td, __ptd, 1); - - - if ( !aaf_get_property( OpGroup, PID_OperationGroup_InputSegments ) && - !aaf_get_property( OpGroup, PID_OperationGroup_Parameters ) ) - { - __td.eob = 1; - } - - - aafObject *ParentMob = get_Object_Ancestor( aafi, OpGroup, &AAFClassID_Mob ); - - if ( ParentMob == NULL ) { - DUMP_OBJ_ERROR( aafi, OpGroup, &__td, "Could not retrieve parent Mob" ); - return -1; - } - - if ( ! aafUIDCmp( ParentMob->Class->ID, &AAFClassID_CompositionMob ) ) { - DUMP_OBJ_ERROR( aafi, OpGroup, &__td, "OperationGroup parser is currently implemented for AAFClassID_CompositionMob children only" ); - return -1; - } - - - aafUID_t *OperationIdentification = get_OperationGroup_OperationIdentification( aafi, OpGroup ); - - - - /* PRINT OPERATIONDEFINITIONS */ - - // aafObject * Parameters = aaf_get_propertyValue( OpGroup, PID_OperationGroup_Parameters ); - // - // if ( Parameters ) { - // aafObject * Param = NULL; - // - // aaf_foreach_ObjectInSet( &Param, Parameters, NULL ) { - // aafUID_t *ParamDef = aaf_get_propertyValue( Param, PID_Parameter_Definition, &AAFTypeID_AUID ); - // debug( " OpDef %ls (%ls) | %ls", aaft_OperationDefToText(aafi->aafd, OperationIdentification), AUIDToText( ParamDef ), aaft_ParameterToText( aafi->aafd, ParamDef ) ); - // } - // } - - - - - - // if ( aafUIDCmp( aafi->ctx.Mob->Class->ID, &AAFClassID_MasterMob ) ) { - // - // /* - // * TODO: This was seen in the spec, but never encountered in real world. - // */ - // - // aafi_trace_obj( aafi, Segment, ANSI_COLOR_RED ); - // error( "MobSlot::Segment > OperationGroup Not implemented yet." ); - // return -1; - // - // } - - - - int rc = 0; - - if ( aafUIDCmp( OpGroup->Parent->Class->ID, &AAFClassID_Transition ) ) { - - aafiTransition *Trans = aafi->ctx.current_transition; - - - if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioDissolve ) ) { + targetMobSlot = aaf_get_MobSlotBySlotID( targetMobSlots, *SourceMobSlotID ); - /* - * Mono Audio Dissolve (Fade, Cross Fade) - * - * The same parameter (curve/level) is applied to the outgoing fade on first - * clip (if any) and to the incoming fade on second clip (if any). + if ( !targetMobSlot ) { + /* TODO check if there is a workaround : + * valgrind --track-origins=yes --leak-check=full ./bin/AAFInfo --trace --aaf-essences --aaf-clips /home/agfline/Programming/libaaf/LibAAF/test/private/aaf/ADP/ADP_STTRACK_CLIPGAIN_TRACKGAIN_XFADE_NOOPTONEXPORT.aaf --verb 3 */ + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve target MobSlot ID : %u", *SourceMobSlotID ); + return -1; + } + } - // __td.eob = 1; - - - - Trans->flags |= AAFI_TRANS_SINGLE_CURVE; - - - int set_default = 0; - - - aafObject * Param = NULL; - aafObject * Parameters = aaf_get_propertyValue( OpGroup, PID_OperationGroup_Parameters, &AAFTypeID_ParameterStrongReferenceVector ); /* opt */ - - if ( Parameters ) { - /* Retrieve AAFParameterDef_Level parameter */ - - aaf_foreach_ObjectInSet( &Param, Parameters, NULL ) { - - aafUID_t *ParamDef = aaf_get_propertyValue( Param, PID_Parameter_Definition, &AAFTypeID_AUID ); - - if ( aafUIDCmp( ParamDef, &AAFParameterDef_Level ) ) - break; - } - } - else { - // DUMP_OBJ_WARNING( aafi, OpGroup, &__td, "Missing PID_OperationGroup_Parameters: Falling back to Linear" ); - set_default = 1; - } - - if ( Param ) { - - DUMP_OBJ( aafi, OpGroup, &__td ); - - if ( aaf_get_property( OpGroup, PID_OperationGroup_InputSegments ) ) { - __td.ll[__td.lv] = 2; - } - - if ( parse_Parameter( aafi, Param, &__td ) < 0 ) { - set_default = 1; - } - - __td.ll[__td.lv] = 0; - } - else { - - /* - * Do not notify exception since this case is standard compliant : - * - * ParameterDef_Level (optional; default is a VaryingValue object with - * two control points: Value 0 at time 0, and value 1 at time 1) - */ - - __td.eob = 1; - DUMP_OBJ( aafi, OpGroup, &__td ); - - // DUMP_OBJ_WARNING( aafi, OpGroup, &__td, "Missing Parameter AAFParameterDef_Level: Setting to Linear" ); - - set_default = 1; - } - - - - if ( set_default ) { - - /* - * ParameterDef_Level (optional; default is a VaryingValue object - * with two control points: Value 0 at time 0, and value 1 at time 1) - * - * This is also a fallback in case of parse_Parameter() failure. - */ - Trans->flags |= AAFI_INTERPOL_LINEAR; + /* *** Clip *** */ - Trans->time_a = calloc( 2, sizeof(aafRational_t) ); - Trans->value_a = calloc( 2, sizeof(aafRational_t) ); + if ( aafUIDCmp( ParentMob->Class->ID, &AAFClassID_CompositionMob ) ) { - Trans->time_a[0].numerator = 0; - Trans->time_a[0].denominator = 0; - Trans->time_a[1].numerator = 1; - Trans->time_a[1].denominator = 1; - if ( Trans->flags & AAFI_TRANS_FADE_IN || - Trans->flags & AAFI_TRANS_XFADE ) - { - Trans->value_a[0].numerator = 0; - Trans->value_a[0].denominator = 0; - Trans->value_a[1].numerator = 1; - Trans->value_a[1].denominator = 1; - } - else - if ( Trans->flags & AAFI_TRANS_FADE_OUT ) { - Trans->value_a[0].numerator = 1; - Trans->value_a[0].denominator = 1; - Trans->value_a[1].numerator = 0; - Trans->value_a[1].denominator = 0; - } - } + int64_t *length = aaf_get_propertyValue( SourceClip, PID_Component_Length, &AAFTypeID_LengthType ); - } - else if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_TwoParameterMonoAudioDissolve ) ) { - DUMP_OBJ_NO_SUPPORT( aafi, OpGroup, &__td ); - /* Two distinct parameters are used for the outgoing and incoming fades. */ - } - else if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_StereoAudioDissolve ) ) { - DUMP_OBJ_NO_SUPPORT( aafi, OpGroup, &__td ); - /* TODO Unknown usage and implementation */ - } - else { - DUMP_OBJ_NO_SUPPORT( aafi, OpGroup, &__td ); + if ( !length ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Missing Component::Length" ); + return -1; } - } - else if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_AudioChannelCombiner ) ) { + int64_t *startTime = aaf_get_propertyValue( SourceClip, PID_SourceClip_StartTime, &AAFTypeID_PositionType ); - DUMP_OBJ( aafi, OpGroup, &__td ); + if ( !startTime ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Missing SourceClip::StartTime" ); + return -1; + } - aafObject *InputSegment = NULL; - aafObject *InputSegments = aaf_get_propertyValue( OpGroup, PID_OperationGroup_InputSegments, &AAFTypeID_SegmentStrongReferenceVector ); + if ( aafUIDCmp( DataDefinition, &AAFDataDef_Sound ) || + aafUIDCmp( DataDefinition, &AAFDataDef_LegacySound ) ) + { - __td.ll[__td.lv] = InputSegments->Header->_entryCount; + if ( aafi->ctx.TopLevelCompositionMob == ParentMob /*!parentMobUsageCode || aafUIDCmp( parentMobUsageCode, &AAFUsage_TopLevel )*/ ) { - aafi->ctx.current_clip_is_combined = 1; - aafi->ctx.current_combined_clip_total_channel = InputSegments->Header->_entryCount; - aafi->ctx.current_combined_clip_channel_num = 0; - aafi->ctx.current_combined_clip_forced_length = 0; + if ( aafi->ctx.current_clip_is_combined && + aafi->ctx.current_combined_clip_channel_num > 0 ) + { + /* + * Parsing multichannel audio clip (AAFOperationDef_AudioChannelCombiner) + * We already parsed the first SourceClip in AAFOperationDef_AudioChannelCombiner. + * We just have to check everything match for all clips left (each clip represents a channel) + * + │ 02277│ ├──◻ AAFClassID_OperationGroup (OpIdent: AAFOperationDef_AudioChannelCombiner; Length: 517207) + │ 02816│ │ ├──◻ AAFClassID_SourceClip (Length: 516000) + │ 02821│ │ │ └──◻ AAFClassID_MasterMob (UsageCode: n/a) : 7 + │ 04622│ │ │ └──◻ AAFClassID_TimelineMobSlot [slot:1 track:1] (DataDef : AAFDataDef_Sound) + │ 03185│ │ │ └──◻ AAFClassID_SourceClip (Length: 523723) + │ 04346│ │ │ └──◻ AAFClassID_SourceMob (UsageCode: n/a) : 7 + │ 01393│ │ │ └──◻ AAFClassID_WAVEDescriptor + │ 01532│ │ │ └──◻ AAFClassID_NetworkLocator : file://localhost/C:/Users/user/Desktop/res/7.1-SMPTE-channel-identif.wav + │ │ │ │ + │ 02666│ │ ├──◻ AAFClassID_SourceClip (Length: 516000) + │ 02666│ │ ├──◻ AAFClassID_SourceClip (Length: 516000) + │ 02666│ │ ├──◻ AAFClassID_SourceClip (Length: 516000) + │ 02666│ │ ├──◻ AAFClassID_SourceClip (Length: 516000) + │ 02666│ │ ├──◻ AAFClassID_SourceClip (Length: 516000) + │ 02666│ │ ├──◻ AAFClassID_SourceClip (Length: 516000) + │ 02666│ │ └──◻ AAFClassID_SourceClip (Length: 516000) + */ - if ( resolve_AAF( aafi ) ) { - /* - * This is clearly a violation of the standard (p 57). When Davinci Resolve - * exports multichannel clips, it does not set SourceClip::Length correctly. - * Insted, it's more like some sort of frame-rounded value which dosn't match - * the timeline. However, the correct value is set to OperationGroup::length. - */ - int64_t *length = aaf_get_propertyValue( OpGroup, PID_Component_Length, &AAFTypeID_LengthType ); - aafi->ctx.current_combined_clip_forced_length = (length) ? *length : 0; - } + if ( aafi->ctx.current_combined_clip_forced_length == 0 && + aafi->ctx.current_clip->len != *length ) + { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "SourceClip length does not match first one in AAFOperationDef_AudioChannelCombiner" ); + return -1; + } - aaf_foreach_ObjectInSet( &InputSegment, InputSegments, NULL ) { + if ( targetMob && !aafUIDCmp( targetMob->Class->ID, &AAFClassID_MasterMob ) ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Multichannel-combined SourceClip does not target a MasterMob: %s", aaft_ClassIDToText( aafi->aafd, targetMob->Class->ID ) ); + return -1; + } - aafi_parse_Segment( aafi, InputSegment, &__td ); + if ( aafMobIDCmp( aafi->ctx.current_clip->essencePointerList->essenceFile->masterMobID, sourceID ) && + aafi->ctx.current_clip->essencePointerList->essenceFile->masterMobSlotID == *SourceMobSlotID ) + { + /* + * Clip channel rely on the same audio file source (single multichannel file) + * + * Assume that all clip channels will point to the same multichannel essence file, in the right order. + * (Davinci Resolve multichannel clips) + */ - aafi->ctx.current_combined_clip_channel_num++; - __td.ll[__td.lv]--; - } + aafi->ctx.current_clip->essencePointerList->essenceChannel = 0; + TRACE_OBJ_INFO( aafi, SourceClip, &__td, "Ignore parsing of clip channel %i pointing to the same audio source file", aafi->ctx.current_combined_clip_channel_num+1 ); + return 0; + } + } - /* - * Sets the track format. - */ - aafiAudioTrack *current_track = (aafiAudioTrack*)aafi->ctx.current_track; + if ( !aafi->ctx.current_clip_is_combined || + (aafi->ctx.current_clip_is_combined && aafi->ctx.current_combined_clip_channel_num == 0) ) + { + /* + * Create new clip, only if we are parsing a single mono clip, or if + * we are parsing the first SourceClip describing the first channel of + * a multichannel clip inside an AAFOperationDef_AudioChannelCombiner + */ - aafiTrackFormat_e track_format = AAFI_TRACK_FORMAT_UNKNOWN; + aafiAudioClip *audioClip = aafi_newAudioClip( aafi, aafi->ctx.current_track ); - if ( aafi->ctx.current_combined_clip_total_channel == 2 ) { - track_format = AAFI_TRACK_FORMAT_STEREO; - } - else if ( aafi->ctx.current_combined_clip_total_channel == 6 ) { - track_format = AAFI_TRACK_FORMAT_5_1; - } - else if ( aafi->ctx.current_combined_clip_total_channel == 8 ) { - track_format = AAFI_TRACK_FORMAT_7_1; - } - else { - DUMP_OBJ_ERROR( aafi, OpGroup, &__td, "Unknown track format (%u)", aafi->ctx.current_combined_clip_total_channel ); + aafiTimelineItem *timelineItem = audioClip->timelineItem; - /* - * Reset multichannel track context. - */ + timelineItem->pos = aafi->ctx.current_track->current_pos; + timelineItem->len = (aafi->ctx.current_combined_clip_forced_length) ? aafi->ctx.current_combined_clip_forced_length : *length; - aafi->ctx.current_clip_is_combined = 0; - aafi->ctx.current_combined_clip_total_channel = 0; - aafi->ctx.current_combined_clip_channel_num = 0; - aafi->ctx.current_combined_clip_forced_length = 0; + audioClip->gain = aafi->ctx.current_clip_gain; + audioClip->automation = aafi->ctx.current_clip_variable_gain; + audioClip->mute = aafi->ctx.current_clip_is_muted; + audioClip->pos = aafi->ctx.current_track->current_pos; - return -1; - } + if ( aafi->ctx.avid_warp_clip_edit_rate ) { + audioClip->essence_offset = aafi_convertUnit( *startTime, aafi->ctx.avid_warp_clip_edit_rate, aafi->ctx.current_track->edit_rate ); + audioClip->len = aafi_convertUnit( (aafi->ctx.current_combined_clip_forced_length) ? aafi->ctx.current_combined_clip_forced_length : *length, aafi->ctx.avid_warp_clip_edit_rate, aafi->ctx.current_track->edit_rate ); + } else { + audioClip->essence_offset = *startTime; + audioClip->len = (aafi->ctx.current_combined_clip_forced_length) ? aafi->ctx.current_combined_clip_forced_length : *length; + } + aafi->ctx.current_track->current_pos += audioClip->len; + aafi->ctx.current_track->clipCount++; - if ( current_track->format != AAFI_TRACK_FORMAT_NOT_SET && - current_track->format != track_format ) - { + aafi->ctx.current_clip_gain_is_used++; + aafi->ctx.current_clip_variable_gain_is_used++; - DUMP_OBJ_ERROR( aafi, OpGroup, &__td, "Track format (%u) does not match current clip (%u)", current_track->format, track_format ); - /* - * Reset multichannel track context. - */ + /* + * ComponentAttributeList is non-standard, but used by Avid Media Composer + * and Davinci Resolve to attach Clip Notes. + */ - aafi->ctx.current_clip_is_combined = 0; - aafi->ctx.current_combined_clip_total_channel = 0; - aafi->ctx.current_combined_clip_channel_num = 0; - aafi->ctx.current_combined_clip_forced_length = 0; + void *ComponentAttributeList = aaf_get_propertyValue( SourceClip, aaf_get_PropertyIDByName( aafi->aafd, "ComponentAttributeList" ), &AAFTypeID_TaggedValueStrongReferenceVector ); - return -1; - } + if ( ComponentAttributeList ) { - current_track->format = track_format; + char *comment = aaf_get_TaggedValueByName( aafi->aafd, ComponentAttributeList, "_COMMENT", &AAFTypeID_String ); + if ( comment ) { + aafiMetaData *meta = aafi_newMetadata( aafi, &audioClip->metadata ); - /* - * Reset multichannel track context. - */ + if ( !meta ) { + warning( "Could not create new Metadata." ); + } + else { + meta->text = comment; + meta->name = laaf_util_c99strdup( "_COMMENT" ); - aafi->ctx.current_clip_is_combined = 0; - aafi->ctx.current_combined_clip_total_channel = 0; - aafi->ctx.current_combined_clip_channel_num = 0; - aafi->ctx.current_combined_clip_forced_length = 0; + if ( !meta->name ) { + error( "Could not duplicate meta name : %s", "_COMMENT" ); + aafiMetaData *tmp = meta->next; + aafi_freeMetadata( &meta ); + audioClip->metadata = tmp; + } + } + } + } + aafi->ctx.current_clip = audioClip; + } - // return; - } - else if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioGain ) ) { + if ( aafi->ctx.current_clip_is_combined == 0 ) { - aafObject * Param = NULL; - aafObject * Parameters = aaf_get_propertyValue( OpGroup, PID_OperationGroup_Parameters, &AAFTypeID_ParameterStrongReferenceVector ); + if ( aafi->ctx.current_track->format != AAFI_TRACK_FORMAT_NOT_SET && + aafi->ctx.current_track->format != AAFI_TRACK_FORMAT_MONO ) + { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Track format (%u) does not match current clip (%u)", aafi->ctx.current_track->format, AAFI_TRACK_FORMAT_MONO ); + } + else { + aafi->ctx.current_track->format = AAFI_TRACK_FORMAT_MONO; + } + } + } + else if ( aafUIDCmp( parentMobUsageCode, &AAFUsage_SubClip ) ) { - if ( Parameters == NULL ) { - DUMP_OBJ_ERROR( aafi, OpGroup, &__td, "Missing PID_OperationGroup_Parameters" ); - rc = -1; goto end; // we still have to parse segments - } + /* Exemple of AAFUsage_SubClip in ../test/private/aaf/AAF/E2R_52min/224E2R190008_ENQUETES_DE_REGION_N32_LA_SECHERESSE_UNE_FATALITE.aaf + * TODO: Looks like a sub-clip is just used to reference an existing clip, but to show it in UI with a different name. + * It seems that sub-clip length always matches MasterMob > SourceLip length + * Therefore, we should only parse its name. + * + │ 02709││ ├──◻ AAFClassID_SourceClip (Length: 183) + │ 02723││ │ └──◻ AAFClassID_CompositionMob (UsageCode: AAFUsage_SubClip) : plato 8 1ere.Copy.01.new.06 (MetaProps: SubclipBegin[0xfff6] SubclipFullLength[0xfff7] MobAttributeList[0xfff9]) + │ 04478││ │ └──◻ AAFClassID_TimelineMobSlot [slot:2 track:2] (DataDef : AAFDataDef_Sound) + │ 02978││ │ └──◻ AAFClassID_SourceClip (Length: 681) + │ 02983││ │ └──◻ AAFClassID_MasterMob (UsageCode: n/a) : FTVHD-X400-0946.new.06 (MetaProps: MobAttributeList[0xfff9] ConvertFrameRate[0xfff8]) + │ 04561││ │ └──◻ AAFClassID_TimelineMobSlot [slot:2 track:2] (DataDef : AAFDataDef_Sound) : FTVHD-X400-0946 + │ 03188││ │ └──◻ AAFClassID_SourceClip (Length: 681) + │ 04305││ │ └──◻ AAFClassID_SourceMob (UsageCode: n/a) : FTVHD-X400-0946.PHYS (MetaProps: MobAttributeList[0xfff9]) + │ 01342││ │ └──◻ AAFClassID_PCMDescriptor (MetaProps: DataOffset[0xffde]) + */ + aafi->ctx.current_clip->subClipName = aaf_get_propertyValue( ParentMob, PID_Mob_Name, &AAFTypeID_String ); - /* Retrieve AAFParameterDef_Amplitude parameter */ + if ( !aafi->ctx.current_clip->subClipName ) { + debug( "Missing parent Mob::Name (sub-clip name)" ); + } - aaf_foreach_ObjectInSet( &Param, Parameters, NULL ) { + aafObject *UserComments = aaf_get_propertyValue( ParentMob, PID_Mob_UserComments, &AAFTypeID_TaggedValueStrongReferenceVector ); - aafUID_t *ParamDef = aaf_get_propertyValue( Param, PID_Parameter_Definition, &AAFTypeID_AUID ); + if ( retrieve_UserComments( aafi, UserComments, &aafi->ctx.current_clip->metadata ) < 0 ) { + warning( "Error parsing parent Mob::UserComments" ); + } + } + else if ( aafUIDCmp( parentMobUsageCode, &AAFUsage_AdjustedClip ) ) { - if ( aafUIDCmp( ParamDef, &AAFParameterDef_Amplitude ) ) - break; - } + // if ( aafi->ctx.current_adjusted_clip_gain ) { + // applyGainOffset( aafi, &aafi->ctx.current_clip->gain, aafi->ctx.current_adjusted_clip_gain ); + // aafi_freeAudioGain( aafi->ctx.current_adjusted_clip_gain ); + // aafi->ctx.current_adjusted_clip_gain = NULL; + // } + } + else if ( !parentMobUsageCode ) { + debug( "CompositionMob UsageCode is NULL. Keep on parsing..." ); + } + else { + debug( "Unsupported CompositionMob UsageCode: %s", aaft_UsageCodeToText( parentMobUsageCode ) ); + TRACE_OBJ_NO_SUPPORT( aafi, SourceClip, &__td ); + return -1; + } - if ( Param == NULL ) { - DUMP_OBJ_ERROR( aafi, OpGroup, &__td, "Missing Parameter ParameterDef_Amplitude" ); - rc = -1; goto end; // we still have to parse segments - } - DUMP_OBJ( aafi, OpGroup, &__td ); + if ( targetMob && aafUIDCmp( targetMob->Class->ID, &AAFClassID_MasterMob ) ) { - __td.ll[__td.lv] = 2; + if ( !targetMobSlot ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Missing target MobSlot" ); + return -1; + } - rc = parse_Parameter( aafi, Param, &__td ); + TRACE_OBJ( aafi, SourceClip, &__td ); - // if ( rc == 0 ) { - // DUMP_OBJ( aafi, OpGroup, &__td ); - // } - // else { - // DUMP_OBJ_ERROR( aafi, OpGroup, &__td, "Failed parsing parameter" ); - // } + __td.lv++; + TRACE_OBJ( aafi, targetMob, &__td ); - } - else if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_StereoAudioGain ) ) { - /* Unknown usage and implementation, not encountered yet */ - DUMP_OBJ_NO_SUPPORT( aafi, OpGroup, &__td ); - } - else if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioPan ) ) { - /* TODO Should Only be Track-based (first Segment of TimelineMobSlot.) */ - /* - * We have to loop because of custom Parameters. - * Seen in AVID Media Composer AAFs (test.aaf). TODO ParamDef PanVol_IsTrimGainEffect ? - */ + parse_MobSlot( aafi, targetMobSlot, &__td ); + } + else if ( targetMob && aafUIDCmp( targetMob->Class->ID, &AAFClassID_CompositionMob ) ) { - aafObject * Param = NULL; - aafObject * Parameters = aaf_get_propertyValue( OpGroup, PID_OperationGroup_Parameters, &AAFTypeID_ParameterStrongReferenceVector ); + /* + * If SourceClip points to a CompositionMob instead of a MasterMob, we + * are at the begining (or inside) a derivation chain. + */ - if ( Parameters == NULL ) { - DUMP_OBJ_ERROR( aafi, OpGroup, &__td, "Missing PID_OperationGroup_Parameters" ); - rc = -1; goto end; // we still have to parse segments - } + TRACE_OBJ( aafi, SourceClip, &__td ); + __td.lv++; + TRACE_OBJ( aafi, targetMob, &__td ); - /* Retrieve AAFParameterDef_Pan parameter */ - aaf_foreach_ObjectInSet( &Param, Parameters, NULL ) { - aafUID_t *ParamDef = aaf_get_propertyValue( Param, PID_Parameter_Definition, &AAFTypeID_AUID ); + parse_MobSlot( aafi, targetMobSlot, &__td ); + } + else { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Targeted Mob no supported: %s", aaft_ClassIDToText( aafi->aafd, targetMob->Class->ID ) ); + return -1; + } - if ( aafUIDCmp( ParamDef, &AAFParameterDef_Pan ) ) - break; } + else if ( aafUIDCmp( DataDefinition, &AAFDataDef_Picture ) || + aafUIDCmp( DataDefinition, &AAFDataDef_LegacyPicture ) ) + { + if ( aafi->ctx.TopLevelCompositionMob != ParentMob ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Current implementation does not support parsing video SourceClip out of TopLevel CompositionMob" ); + return -1; + } - if ( Param == NULL ) { - DUMP_OBJ_ERROR( aafi, OpGroup, &__td, "Missing Parameter ParameterDef_Amplitude" ); - rc = -1; goto end; // we still have to parse segments - } + if ( aafi->Video->Tracks->timelineItems ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Current implementation supports only one video clip" ); + return -1; + } + /* Add the new clip */ - DUMP_OBJ( aafi, OpGroup, &__td ); + aafiVideoClip *videoClip = aafi_newVideoClip( aafi, aafi->Video->Tracks ); - __td.ll[__td.lv] = 2; + aafiTimelineItem *timelineItem = videoClip->timelineItem; - rc = parse_Parameter( aafi, Param, &__td ); + timelineItem->pos = aafi->Video->Tracks->current_pos; + timelineItem->len = *length; - // if ( rc == 0 ) { - // DUMP_OBJ( aafi, OpGroup, &__td ); - // } - // else { - // DUMP_OBJ_ERROR( aafi, OpGroup, &__td, "Failed parsing parameter" ); - // } - } - else if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioMixdown ) ) { - DUMP_OBJ_NO_SUPPORT( aafi, OpGroup, &__td ); - /* TODO Unknown usage and implementation */ - } - else { - DUMP_OBJ_NO_SUPPORT( aafi, OpGroup, &__td ); - } + videoClip->pos = aafi->Video->Tracks->current_pos; + videoClip->len = *length; + videoClip->essence_offset = *startTime; + aafi->Video->Tracks->current_pos += videoClip->len; + aafi->ctx.current_video_clip = videoClip; -end: - /* - * Parses Segments in the OperationGroup::InputSegments, only if - * OperationGroup is not a Transition as a Transition has no InputSegments, - * and not an AudioChannelCombiner as they were already parsed. - */ + if ( targetMob && aafUIDCmp( targetMob->Class->ID, &AAFClassID_MasterMob ) ) { - if ( aafUIDCmp( OpGroup->Parent->Class->ID, &AAFClassID_Transition ) == 0 && - aafUIDCmp( OperationIdentification, &AAFOperationDef_AudioChannelCombiner ) == 0 ) - { - aafObject *InputSegment = NULL; - aafObject *InputSegments = aaf_get_propertyValue( OpGroup, PID_OperationGroup_InputSegments, &AAFTypeID_SegmentStrongReferenceVector ); + if ( !targetMobSlot ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Missing target MobSlot" ); + return -1; + } + + TRACE_OBJ( aafi, SourceClip, &__td ); + + __td.lv++; + TRACE_OBJ( aafi, targetMob, &__td ); - int i = 0; - __td.ll[__td.lv] = (InputSegments) ? InputSegments->Header->_entryCount : 0; - aaf_foreach_ObjectInSet( &InputSegment, InputSegments, NULL ) { - __td.ll[__td.lv] = __td.ll[__td.lv] - i++; - aafi_parse_Segment( aafi, InputSegment, &__td ); + parse_MobSlot( aafi, targetMobSlot, &__td ); + } + else { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Current implementation does not support video SourceClip not targetting a MasterMob: %s", (targetMob) ? aaft_ClassIDToText( aafi->aafd, targetMob->Class->ID ) : "[MISSING TARGET MOB]" ); + return -1; + } } } - /* End of current OperationGroup context. */ - aafObject *Obj = OpGroup; - for (; Obj != NULL && aafUIDCmp( Obj->Class->ID, &AAFClassID_ContentStorage ) == 0; Obj = Obj->Parent ) - if ( !aafUIDCmp( Obj->Class->ID, &AAFClassID_OperationGroup ) ) - break; + /* *** Essence *** */ - if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioGain ) ) { + else if ( aafUIDCmp( ParentMob->Class->ID, &AAFClassID_MasterMob ) ) { - if ( !aafUIDCmp( Obj->Class->ID, &AAFClassID_TimelineMobSlot ) ) { + aafMobID_t *masterMobID = aaf_get_propertyValue( ParentMob, PID_Mob_MobID, &AAFTypeID_MobIDType ); - if ( aafi->ctx.clips_using_gain == 0 ) { - aafi_freeAudioGain( aafi->ctx.current_clip_gain ); - } + if ( !masterMobID ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Missing parent Mob::MobID" ); + return -1; + } - if ( aafi->ctx.clips_using_automation == 0 ) { - aafi_freeAudioGain( aafi->ctx.current_clip_automation ); - } + aafObject *ParentMobSlot = aaf_get_ObjectAncestor( SourceClip, &AAFClassID_MobSlot ); - /* Clip-based Gain */ - aafi->ctx.current_clip_is_muted = 0; - aafi->ctx.current_clip_gain = NULL; - aafi->ctx.current_clip_automation = NULL; - aafi->ctx.clips_using_gain = 0; - aafi->ctx.clips_using_automation = 0; + if ( !ParentMobSlot ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve parent MobSlot" ); + return -1; } - // free( aafi->ctx.current_track->gain ); - // aafi->ctx.current_track->gain = NULL; - } + uint32_t *masterMobSlotID = aaf_get_propertyValue( ParentMobSlot, PID_MobSlot_SlotID, &AAFTypeID_UInt32 ); - return rc; -} + uint32_t *essenceChannelNum = aaf_get_propertyValue( ParentMobSlot, PID_MobSlot_PhysicalTrackNumber, &AAFTypeID_UInt32 ); + if ( aafUIDCmp( DataDefinition, &AAFDataDef_Sound ) || + aafUIDCmp( DataDefinition, &AAFDataDef_LegacySound ) ) + { -static int parse_SourceClip( AAF_Iface *aafi, aafObject *SourceClip, td *__ptd ) -{ + if ( !aafi->ctx.current_clip ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "aafi->ctx.current_clip not set" ); + return -1; + } - struct trace_dump __td; - __td_set(__td, __ptd, 1); + /* + * Check if this Essence has already been retrieved + */ - __td.hc = 1; // link to MasterMob, SourceMob + aafiAudioEssenceFile *audioEssenceFile = NULL; + AAFI_foreachAudioEssenceFile( aafi, audioEssenceFile ) { + if ( aafMobIDCmp( audioEssenceFile->sourceMobID, sourceID ) && audioEssenceFile->sourceMobSlotID == (unsigned)*SourceMobSlotID ) { + __td.eob = 1; + TRACE_OBJ_INFO( aafi, SourceClip, &__td, "Essence already parsed: Linking with %s", audioEssenceFile->name ); + aafi->ctx.current_clip->essencePointerList = aafi_newAudioEssencePointer( aafi, &aafi->ctx.current_clip->essencePointerList, audioEssenceFile, essenceChannelNum ); + return 0; + } + } - aafUID_t *DataDefinition = get_Component_DataDefinition( aafi, SourceClip ); + /* new Essence, carry on. */ - if ( DataDefinition == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve DataDefinition" ); - return -1; - } + audioEssenceFile = aafi_newAudioEssence( aafi ); + audioEssenceFile->masterMobSlotID = *masterMobSlotID; + audioEssenceFile->masterMobID = masterMobID; + audioEssenceFile->name = aaf_get_propertyValue( ParentMob, PID_Mob_Name, &AAFTypeID_String ); - aafObject *ParentMob = get_Object_Ancestor( aafi, SourceClip, &AAFClassID_Mob ); + if ( audioEssenceFile->name == NULL ) { + debug( "Missing parent Mob::Name (essence file name)" ); + } - if ( ParentMob == NULL ) { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve parent Mob" ); - return -1; - } + audioEssenceFile->sourceMobSlotID = *SourceMobSlotID; + audioEssenceFile->sourceMobID = sourceID; - aafMobID_t *parentMobID = aaf_get_propertyValue( ParentMob, PID_Mob_MobID, &AAFTypeID_MobIDType ); - if ( parentMobID == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Missing parent Mob PID_Mob_MobID" ); - return -1; - } + aafObject *SourceMob = aaf_get_MobByID( aafi->aafd->Mobs, audioEssenceFile->sourceMobID ); + if ( !SourceMob ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve SourceMob by ID : %s", aaft_MobIDToText(audioEssenceFile->sourceMobID) ); + return -1; + } + aafi->ctx.current_audio_essence = audioEssenceFile; - aafMobID_t *sourceID = aaf_get_propertyValue( SourceClip, PID_SourceReference_SourceID, &AAFTypeID_MobIDType ); - if ( sourceID == NULL ) { /* opt */ - /* NOTE: PID_SourceReference_SourceID is optionnal, there might be none. */ - // DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Missing PID_SourceReference_SourceID" ); - // return -1; - } + void *MobUserComments = aaf_get_propertyValue( ParentMob, PID_Mob_UserComments, &AAFTypeID_TaggedValueStrongReferenceVector ); - uint32_t *SourceMobSlotID = aaf_get_propertyValue( SourceClip, PID_SourceReference_SourceMobSlotID, &AAFTypeID_UInt32 ); + if ( retrieve_UserComments( aafi, MobUserComments, &audioEssenceFile->metadata ) < 0 ) { + TRACE_OBJ_WARNING( aafi, SourceClip, &__td, "Error parsing parent Mob::UserComments" ); + } else { + TRACE_OBJ( aafi, SourceClip, &__td ); + } - if ( SourceMobSlotID == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Missing PID_SourceReference_SourceMobSlotID" ); - return -1; - } - /* - * TODO: handle SourceReference::MonoSourceSlotIDs and associated conditional rules. - * (Multi-channels) - */ + audioEssenceFile->SourceMob = SourceMob; - aafObject *targetMob = NULL; - aafObject *targetMobSlot = NULL; - aafUID_t *targetMobUsageCode = NULL; + aafObject *EssenceData = aaf_get_EssenceDataByMobID( aafi->aafd, audioEssenceFile->sourceMobID ); - if ( sourceID == NULL ) { - /* - * p.49 : To create a SourceReference that refers to a MobSlot within - * the same Mob as the SourceReference, omit the SourceID property. - * - * [SourceID] Identifies the Mob being referenced. If the property has a - * value 0, it means that the Mob owning the SourceReference describes - * the original source. - * - * TODO: in that case, is MobSlots NULL ? - */ + if ( EssenceData ) + __td.ll[__td.lv] = 2; - // sourceID = parentMobID; - // targetMob = ParentMob; - } - else { - targetMob = aaf_get_MobByID( aafi->aafd->Mobs, sourceID ); + parse_Mob( aafi, SourceMob, &__td ); - if ( targetMob == NULL ) { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve target Mob by ID : %ls", aaft_MobIDToText(sourceID) ); - return -1; - } + if ( EssenceData ) + __td.ll[__td.lv] = 1; - targetMobUsageCode = aaf_get_propertyValue( targetMob, PID_Mob_UsageCode, &AAFTypeID_UsageType ); + if ( EssenceData ) { + /* If EssenceData was found, it means essence is embedded */ + parse_EssenceData( aafi, EssenceData, &__td ); + __td.ll[__td.lv] = 0; + } - aafObject *targetMobSlots = aaf_get_propertyValue( targetMob, PID_Mob_Slots, &AAFTypeID_MobSlotStrongReferenceVector ); + aafi_build_unique_audio_essence_name( aafi, audioEssenceFile ); - if ( targetMobSlots == NULL ) { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Missing target Mob PID_Mob_Slots" ); - return -1; + aafi->ctx.current_clip->essencePointerList = aafi_newAudioEssencePointer( aafi, &aafi->ctx.current_clip->essencePointerList, audioEssenceFile, essenceChannelNum ); + aafi->ctx.current_audio_essence = NULL; } + else if ( aafUIDCmp( DataDefinition, &AAFDataDef_Picture ) || + aafUIDCmp( DataDefinition, &AAFDataDef_LegacyPicture ) ) + { - targetMobSlot = aaf_get_MobSlotBySlotID( targetMobSlots, *SourceMobSlotID ); + if ( !aafi->ctx.current_video_clip ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "aafi->ctx.current_video_clip not set" ); + return -1; + } - if ( targetMobSlot == NULL ) { - /* TODO check if there is a workaround : - * AAFInfo --aaf-clips '/home/agfline/Developpement/libaaf_testfiles/ADP/ADP_STTRACK_CLIPGAIN_TRACKGAIN_XFADE_NOOPTONEXPORT.aaf' + /* + * Check if this Essence has already been retrieved */ - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve target MobSlot ID : %u", *SourceMobSlotID ); - return -1; - } - } - + aafiVideoEssence *videoEssenceFile = NULL; + AAFI_foreachVideoEssence( aafi, videoEssenceFile ) { + if ( aafMobIDCmp( videoEssenceFile->sourceMobID, sourceID ) && videoEssenceFile->sourceMobSlotID == (unsigned)*SourceMobSlotID ) { + __td.eob = 1; + TRACE_OBJ_INFO( aafi, SourceClip, &__td, "Essence already parsed: Linking with %s", videoEssenceFile->name ); + aafi->ctx.current_video_clip->Essence = videoEssenceFile; + return 0; + } + } - /* *** Clip *** */ + /* new Essence, carry on. */ - if ( aafUIDCmp( ParentMob->Class->ID, &AAFClassID_CompositionMob ) ) { + videoEssenceFile = aafi_newVideoEssence( aafi ); - // DUMP_OBJ( aafi, SourceClip, &__td ); + aafi->ctx.current_video_clip->Essence = videoEssenceFile; + videoEssenceFile->masterMobSlotID = *masterMobSlotID; + videoEssenceFile->masterMobID = masterMobID; + videoEssenceFile->name = aaf_get_propertyValue( ParentMob, PID_Mob_Name, &AAFTypeID_String ); - int64_t *length = aaf_get_propertyValue( SourceClip, PID_Component_Length, &AAFTypeID_LengthType ); + if ( videoEssenceFile->name == NULL ) { + debug( "Missing parent Mob::Name (essence file name)" ); + } - if ( length == NULL ) { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Missing PID_Component_Length" ); - return -1; - } + videoEssenceFile->sourceMobSlotID = *SourceMobSlotID; + videoEssenceFile->sourceMobID = sourceID; - int64_t *startTime = aaf_get_propertyValue( SourceClip, PID_SourceClip_StartTime, &AAFTypeID_PositionType ); + TRACE_OBJ( aafi, SourceClip, &__td ); - if ( startTime == NULL ) { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Missing PID_SourceClip_StartTime" ); - return -1; - } + aafObject *SourceMob = aaf_get_MobByID( aafi->aafd->Mobs, videoEssenceFile->sourceMobID ); + if ( !SourceMob ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve SourceMob by ID : %s", aaft_MobIDToText(videoEssenceFile->sourceMobID) ); + return -1; + } + videoEssenceFile->SourceMob = SourceMob; - struct aafiContext ctxBackup; + aafi->ctx.current_video_essence = videoEssenceFile; - aafUID_t *CurrentUsageCode = aaf_get_propertyValue( ParentMob, PID_Mob_UsageCode, &AAFTypeID_UsageType ); + aafObject *EssenceData = aaf_get_EssenceDataByMobID( aafi->aafd, videoEssenceFile->sourceMobID ); - if ( CurrentUsageCode == NULL ) { - /* NOTE: PID_Mob_UsageCode is optionnal, there might be none. */ - // DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Missing PID_Mob_UsageCode" ); - // return -1; - } - // if ( aafUIDCmp( aafi->aafd->Header.OperationalPattern, &AAFOPDef_EditProtocol ) ) - { + parse_Mob( aafi, SourceMob, &__td ); - // if ( (CurrentUsageCode && aafUIDCmp( CurrentUsageCode, &AAFUsage_SubClip )) || CurrentUsageCode == NULL ) { - // aafi_trace_obj( aafi, SourceClip, ANSI_COLOR_YELLOW ); - // } - // else { - // aafi_trace_obj( aafi, SourceClip, ANSI_COLOR_MAGENTA ); - // } + if ( EssenceData ) { + /* + * It means essence is embedded, otherwise it's not. + */ + parse_EssenceData( aafi, EssenceData, &__td ); + } /* - * If SourceClip points to a CompositionMob instead of a MasterMob, we - * are at the begining (or inside) a derivation chain. + * No need to check for uniqueness, current version supports only one video clip. */ + videoEssenceFile->unique_name = laaf_util_c99strdup( videoEssenceFile->name ); - if ( aafUIDCmp( targetMob->Class->ID, &AAFClassID_CompositionMob ) ) { - - DUMP_OBJ( aafi, SourceClip, &__td ); + if ( !videoEssenceFile->unique_name ) { + TRACE_OBJ_ERROR( aafi, SourceClip, &__td, "Could not duplicate video essence unique name : %s", videoEssenceFile->name ); + return -1; + } + aafi->ctx.current_video_essence = NULL; + } + } + else if ( aafUIDCmp( ParentMob->Class->ID, &AAFClassID_SourceMob ) ) { + /* Nothing to parse here at first glance : SourceMob > TimelineMobSlot > SourceClip */ + TRACE_OBJ( aafi, SourceClip, &__td ); + } + else { + TRACE_OBJ_NO_SUPPORT( aafi, SourceClip, &__td ); + return -1; + } + return 0; +} - /* Only to print trace */ - __td.lv++; - DUMP_OBJ( aafi, targetMob, &__td ); - // __td.lv++; - memcpy( &ctxBackup, &(aafi->ctx), sizeof(struct aafiContext) ); +static int parse_Timecode( AAF_Iface *aafi, aafObject *Timecode, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 1); + __td.eob = 1; - RESET_CONTEXT( aafi->ctx ); - aafi->ctx.current_track = ctxBackup.current_track; - aafi->ctx.is_inside_derivation_chain = 1; + aafPosition_t *tc_start = aaf_get_propertyValue( Timecode, PID_Timecode_Start, &AAFTypeID_PositionType ); - parse_MobSlot( aafi, targetMobSlot, &__td ); + if ( tc_start == NULL ) { + TRACE_OBJ_ERROR( aafi, Timecode, &__td, "Missing Timecode::Start" ); + return -1; + } - void *new_clip = aafi->ctx.current_clip; - memcpy( &(aafi->ctx), &ctxBackup, sizeof(struct aafiContext) ); + uint16_t *tc_fps = aaf_get_propertyValue( Timecode, PID_Timecode_FPS, &AAFTypeID_UInt16 ); + if ( tc_fps == NULL ) { + TRACE_OBJ_ERROR( aafi, Timecode, &__td, "Missing Timecode::FPS" ); + return -1; + } - if ( aafUIDCmp( DataDefinition, &AAFDataDef_Sound ) || - aafUIDCmp( DataDefinition, &AAFDataDef_LegacySound ) ) - { - aafi->ctx.current_clip = (aafiAudioClip*)new_clip; + uint8_t *tc_drop = aaf_get_propertyValue( Timecode, PID_Timecode_Drop, &AAFTypeID_UInt8 ); - if ( new_clip && aafUIDCmp( CurrentUsageCode, &AAFUsage_TopLevel ) ) { + if ( tc_drop == NULL ) { + TRACE_OBJ_ERROR( aafi, Timecode, &__td, "Missing Timecode::Drop" ); + return -1; + } - /* - * All derivation chain calls ended. - * - * We came back at level zero of parse_SourceClip() nested calls, so - * the clip and its source was added, we only have to set its length, - * offset and gain with correct values. - * - * TODO: aafi->current_clip pointer to new_clip instead ? - */ - ((aafiAudioClip*)new_clip)->len = (aafi->ctx.current_combined_clip_forced_length) ? aafi->ctx.current_combined_clip_forced_length : *length; - ((aafiAudioClip*)new_clip)->essence_offset = *startTime; - ((aafiAudioClip*)new_clip)->gain = aafi->ctx.current_clip_gain; - ((aafiAudioClip*)new_clip)->automation = aafi->ctx.current_clip_automation; - ((aafiAudioClip*)new_clip)->mute = aafi->ctx.current_clip_is_muted; - aafi->ctx.clips_using_gain++; - aafi->ctx.clips_using_automation++; + /* TODO this should be retrieved directly from TimelineMobSlot */ - aafi->ctx.current_track->current_pos += ((aafiAudioClip*)new_clip)->len; - } - } - else - if ( aafUIDCmp( DataDefinition, &AAFDataDef_Picture ) || - aafUIDCmp( DataDefinition, &AAFDataDef_LegacyPicture ) ) - { + aafObject *ParentMobSlot = aaf_get_ObjectAncestor( Timecode, &AAFClassID_MobSlot ); - if ( new_clip && aafUIDCmp( CurrentUsageCode, &AAFUsage_TopLevel ) ) { + if ( !ParentMobSlot ) { + TRACE_OBJ_ERROR( aafi, Timecode, &__td, "Could not retrieve parent MobSlot" ); + return -1; + } - /* - * All derivation chain calls ended. - * - * We came back at level zero of parse_SourceClip() nested calls, so - * the clip and its source was added, we only have to set its length, - * offset and gain with correct values. - */ + aafRational_t *tc_edit_rate = aaf_get_propertyValue( ParentMobSlot, PID_TimelineMobSlot_EditRate, &AAFTypeID_Rational ); - ((aafiVideoClip*)new_clip)->len = (aafi->ctx.current_combined_clip_forced_length) ? aafi->ctx.current_combined_clip_forced_length : *length; - ((aafiVideoClip*)new_clip)->essence_offset = *startTime; + if ( tc_edit_rate == NULL ) { + TRACE_OBJ_ERROR( aafi, Timecode, &__td, "Missing parent TimelineMobSlot::EditRate" ); + return -1; + } - aafi->Video->Tracks->current_pos += ((aafiVideoClip*)new_clip)->len; - } - } - return 0; + if ( aafi->Timecode ) { + TRACE_OBJ_WARNING( aafi, Timecode, &__td, "Timecode was already set, ignoring (%lu, %u fps)", *tc_start, *tc_fps ); + return -1; + } - } - else if ( aafUIDCmp( targetMob->Class->ID, &AAFClassID_MasterMob ) ) { - /* - * We are inside the derivation chain and we reached the SourceClip - * pointing to MasterMob (the audio essence). - * - * Thus, we can add the clip and parse the audio essence normaly. - */ - } - } + aafiTimecode *tc = calloc( 1, sizeof(aafiTimecode) ); + if ( !tc ) { + TRACE_OBJ_ERROR( aafi, Timecode, &__td, "Out of memory" ); + return -1; + } - if ( aafUIDCmp( DataDefinition, &AAFDataDef_Sound ) || - aafUIDCmp( DataDefinition, &AAFDataDef_LegacySound ) ) - { + tc->start = *tc_start; + tc->fps = *tc_fps; + tc->drop = *tc_drop; + tc->edit_rate = tc_edit_rate; - // if ( *length == 1 ) { - // /* - // * If length equals 1 EditUnit, the clip is probably a padding for "Media Composer Compatibility". - // * Therefore, we don't need it. - // * - // * TODO BUT this could also be some rendered fade.. we should find a way to distinguish between the two. - // */ - // - // // aaf_dump_ObjectProperties( aafi->aafd, SourceClip ); - // - // warning( "Got a 1 EU length clip, probably some NLE compatibility padding : Skipping." ); - // - // - // - // if ( aafi->ctx.current_track_is_multichannel == 0 ) { - // aafi->ctx.current_pos += *length; - // } - // else { - // aafi->ctx.current_multichannel_track_clip_length = *length; - // } - // - // return -1; - // } - - - - - - if ( aafi->ctx.current_clip_is_combined && - aafi->ctx.current_combined_clip_channel_num > 0 ) - { + aafi->Timecode = tc; - /* - * Parsing multichannel audio clip (AAFOperationDef_AudioChannelCombiner) - * We already parsed first SourceClip in AAFOperationDef_AudioChannelCombiner. - * We just have to check everything match for all clips left (each clip represents a channel) - */ - if ( aafi->ctx.current_combined_clip_forced_length == 0 && aafi->ctx.current_clip->len != *length ) { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "SourceClip length does not match first one in AAFOperationDef_AudioChannelCombiner" ); - return -1; - } + TRACE_OBJ( aafi, Timecode, &__td ); - if ( aafMobIDCmp( aafi->ctx.current_clip->essencePointerList->essence->masterMobID, sourceID ) ) { - /* - * Clip channel rely on the same audio file source (single multichannel file) - * - * Assume that all clip channels will point to the same multichannel essence file, in the right order. - * (Davinci Resolve multichannel clips) - */ - aafi->ctx.current_clip->essencePointerList->essenceChannel = 0; + return 0; +} - DUMP_OBJ( aafi, SourceClip, &__td ); - return 0; - } - } - aafiAudioClip *audioClip = NULL; +static int parse_DescriptiveMarker( AAF_Iface *aafi, aafObject *DescriptiveMarker, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 1); - if ( !aafi->ctx.current_clip_is_combined || (aafi->ctx.current_clip_is_combined && aafi->ctx.current_combined_clip_channel_num == 0) ) - { - /* - * Create new clip, only if we are parsing a single mono clip, or if - * we are parsing the first SourceClip describing a multichannel clip - * inside an AAFOperationDef_AudioChannelCombiner - */ - aafiTimelineItem *item = aafi_newTimelineItem( aafi, aafi->ctx.current_track, AAFI_AUDIO_CLIP ); + aafPosition_t *start = aaf_get_propertyValue( DescriptiveMarker, PID_Event_Position, &AAFTypeID_PositionType ); - audioClip = item->data;//(aafiAudioClip*)&item->data; + if ( !start ) { + /* + * « If an Event is in a TimelineMobSlot or a StaticMobSlot, it shall not have a Position + * property. If an Event is in a EventMobSlot, it shall have a Position property. » + */ + TRACE_OBJ_ERROR( aafi, DescriptiveMarker, &__td, "Missing Event::Position" ); + return -1; + } - aafi->ctx.clips_using_gain++; - aafi->ctx.clips_using_automation++; - audioClip->gain = aafi->ctx.current_clip_gain; - audioClip->automation = aafi->ctx.current_clip_automation; - audioClip->mute = aafi->ctx.current_clip_is_muted; - audioClip->pos = aafi->ctx.current_track->current_pos; - audioClip->len = (aafi->ctx.current_combined_clip_forced_length) ? aafi->ctx.current_combined_clip_forced_length : *length; + TRACE_OBJ( aafi, DescriptiveMarker, &__td ); - audioClip->essence_offset = *startTime; - aafi->ctx.current_clip = audioClip; - } - else { - /* clip is multichannel and we are parsing SourceClip channel > first channel */ - audioClip = aafi->ctx.current_clip; - } + aafPosition_t *length = aaf_get_propertyValue( DescriptiveMarker, PID_Component_Length, &AAFTypeID_PositionType ); + char *comment = aaf_get_propertyValue( DescriptiveMarker, PID_Event_Comment, &AAFTypeID_String ); + char *name = aaf_get_propertyValue( DescriptiveMarker, aaf_get_PropertyIDByName( aafi->aafd, "CommentMarkerUser" ), &AAFTypeID_String ); + if ( !name ) { + /* Avid Media Composer 23.12 */ + name = aaf_get_propertyValue( DescriptiveMarker, aaf_get_PropertyIDByName( aafi->aafd, "CommentMarkerUSer" ), &AAFTypeID_String ); + } + uint16_t *RGBColor = NULL; + aafProperty *RGBColorProp = aaf_get_property( DescriptiveMarker, aaf_get_PropertyIDByName( aafi->aafd, "CommentMarkerColor" ) ); - if ( !aafi->ctx.is_inside_derivation_chain && - (!aafi->ctx.current_clip_is_combined || (aafi->ctx.current_clip_is_combined && aafi->ctx.current_combined_clip_channel_num == 0)) ) - { + if ( RGBColorProp ) { - /* - * We update ONLY ONCE when SourceClip belongs to a OpGroup AAFOperationDef_AudioChannelCombiner. - * - * We DO NOT update current pos when SourceClip belongs to a sub CompositionMob - * because in that case, current pos was already updated by initial SourceClip - * pointing to AAFClassID_CompositionMob - -04606│├──◻ AAFClassID_TimelineMobSlot [slot:16 track:8] (DataDef : AAFDataDef_LegacySound) -02064││ └──◻ AAFClassID_Sequence -02037││ ├──◻ AAFClassID_Filler - ││ │ -02502││ ├──◻ AAFClassID_OperationGroup (OpIdent: AAFOperationDef_MonoAudioGain) (MetaProps: ComponentAttributeList[0xffcc]) -03780││ │ ├──◻ AAFClassID_ConstantValue -POS UPDATED HERE --> └──◻ AAFClassID_SourceClip -02842││ │ └──◻ AAFClassID_CompositionMob (UsageCode: AAFUsage_AdjustedClip) : Islamic Call to Prayer - Amazing Adhan by Edris Aslami.mp3.new.01 (MetaProps: MobAttributeList[0xfff9] ConvertFrameRate[0xfff8]) -04606││ │ └──◻ AAFClassID_TimelineMobSlot [slot:2 track:2] (DataDef : AAFDataDef_LegacySound) -02502││ │ └──◻ AAFClassID_OperationGroup (OpIdent: AAFOperationDef_MonoAudioGain) -03780││ │ ├──◻ AAFClassID_ConstantValue -POS NOT UPDATED HERE ------------------> └──◻ AAFClassID_SourceClip -03085││ │ └──◻ AAFClassID_MasterMob (UsageCode: n/a) : Islamic Call to Prayer - Amazing Adhan by Edris Aslami.mp3.new.01 (MetaProps: AppCode[0xfffa]) -04705││ │ └──◻ AAFClassID_TimelineMobSlot -03305││ │ └──◻ AAFClassID_SourceClip -04412││ │ └──◻ AAFClassID_SourceMob (UsageCode: n/a) : Islamic Call to Prayer - Amazing Adhan by Edris Aslami.mp3 (MetaProps: MobAttributeList[0xfff9]) -01400││ │ └──◻ AAFClassID_WAVEDescriptor -01555││ │ └──◻ AAFClassID_NetworkLocator : file:///MEDIA2/2199_Rapport_Astellas Main Content/audio/AX TEST.aaf + if ( RGBColorProp->len != sizeof(uint16_t)*3 ) { + error( "CommentMarkerColor has wrong size: %u", RGBColorProp->len ); + } + else { + RGBColor = RGBColorProp->val; - */ + /* big endian to little endian */ + RGBColor[0] = (RGBColor[0]>>8) | (RGBColor[0]<<8); + RGBColor[1] = (RGBColor[1]>>8) | (RGBColor[1]<<8); + RGBColor[2] = (RGBColor[2]>>8) | (RGBColor[2]<<8); + } + } - aafi->ctx.current_track->current_pos += (aafi->ctx.current_combined_clip_forced_length) ? aafi->ctx.current_combined_clip_forced_length : audioClip->len; - } + aafi_newMarker( aafi, aafi->ctx.current_markers_edit_rate, *start, ((length) ? *length : 0), name, comment, &RGBColor ); + return 0; +} - if ( aafi->ctx.current_clip_is_combined == 0 ) { - if ( aafi->ctx.current_track->format != AAFI_TRACK_FORMAT_NOT_SET && - aafi->ctx.current_track->format != AAFI_TRACK_FORMAT_MONO ) - { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Track format (%u) does not match current clip (%u)", aafi->ctx.current_track->format, AAFI_TRACK_FORMAT_MONO ); - } - else { - aafi->ctx.current_track->format = AAFI_TRACK_FORMAT_MONO; - } - } +static int parse_Sequence( AAF_Iface *aafi, aafObject *Sequence, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 1); - if ( aafUIDCmp( targetMob->Class->ID, &AAFClassID_MasterMob ) ) { + aafObject *Component = NULL; + aafObject *Components = aaf_get_propertyValue( Sequence, PID_Sequence_Components, &AAFTypeID_ComponentStrongReferenceVector ); - if ( targetMobSlot == NULL ) { - /* TODO isn't it already checked above ? */ - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Missing target MobSlot" ); - return -1; - } + if ( !Components ) { + TRACE_OBJ_ERROR( aafi, Sequence, &__td, "Missing Sequence::Components" ); + return -1; + } - DUMP_OBJ( aafi, SourceClip, &__td ); + TRACE_OBJ( aafi, Sequence, &__td ); - /* Only to print trace */ - __td.lv++; - DUMP_OBJ( aafi, targetMob, &__td ); + /* + * "Audio Warp" OperationGroup appears in Avid Media Composer AAF files, when + * a clip with a different frame rate from the project was *linked* into Avid + * rather than beeing properly imported. + * + * "Audio Warp" OperationGroup is pointing to a Sequence with two ComponentAttributes: + * _MIXMATCH_RATE_NUM + * _MIXMATCH_RATE_DENOM + * + * Those parameters set the valid edit rate for SourceClip::StartTime (essence + * offset) and Component::Length, in total violation of the standard saying that + * TimelineMobSlot::EditRate shall always be used. + * +│ 02009││ │ ├──◻ AAFClassID_OperationGroup (OpIdent: Audio Warp; Length: 168) (MetaProps: ComponentAttributeList[0xffc9]) +│ 02283││ │ │ ├──◻ AAFClassID_ConstantValue (ParamDef: AvidMotionInputFormat; Type: AAFTypeID_Int32) : 2 +│ 02283││ │ │ ├──◻ AAFClassID_ConstantValue (ParamDef: AAFParameterDef_SpeedRatio; Type: AAFTypeID_Rational) : 1/2 +│ 02283││ │ │ ├──◻ AAFClassID_ConstantValue (ParamDef: AvidPhase; Type: AAFTypeID_Int32) : 0 +│ 02283││ │ │ ├──◻ AAFClassID_ConstantValue (ParamDef: AvidMotionOutputFormat; Type: AAFTypeID_Int32) : 0 +│ 02283││ │ │ └──◻ AAFClassID_ConstantValue (ParamDef: AvidMotionPulldown; Type: AAFTypeID_Int32) : 0 +│ 01628││ │ │ └──◻ AAFClassID_Sequence (Length: 336) (MetaProps: ComponentAttributeList[0xffc9]) +│ 01195││ │ │ └──◻ AAFClassID_SourceClip (Length: 336) +│ 01198││ │ │ └──◻ AAFClassID_MasterMob (UsageCode: n/a) : UTS_LIMO_LIMO_3_2024_01_30_11_15_45.new.04 (MetaProps: MobAttributeList[0xfff9] ConvertFrameRate[0xfff8]) +│ 00513││ │ │ └──◻ AAFClassID_TimelineMobSlot [slot:1 track:1] (DataDef: AAFDataDef_Sound) +│ 01628││ │ │ └──◻ AAFClassID_Sequence (Length: 576) +│ 01359││ │ │ └──◻ AAFClassID_SourceClip (Length: 576) +│ 00272││ │ │ ├──◻ AAFClassID_SourceMob (UsageCode: n/a) (MetaProps: MobAttributeList[0xfff9]) +│ 02806││ │ │ │ ├──◻ AAFClassID_WAVEDescriptor (ContainerIdent : AAFContainerDef_AAF) +│ 03010││ │ │ │ │ └──◻ AAFClassID_NetworkLocator (URLString: file://10.87.230.71/mixage/AAF_Vers_Mixage/MONTAGE_06/4550985%20SUIVI%20AGRICULTEURS%20VERS%20PARIS.aaf) +│ ││ │ │ │ │ +│ 00532││ │ │ │ └──◻ AAFClassID_TimelineMobSlot [slot:1 track:1] (DataDef: AAFDataDef_Sound) +│ 01470││ │ │ │ └──◻ AAFClassID_SourceClip (Length: 576) +│ 03071││ │ │ └──◻ AAFClassID_EssenceData (Data: Data-2702) - memcpy( &ctxBackup, &(aafi->ctx), sizeof(struct aafiContext) ); + */ - /* TODO: Commented out to avoid reset of ctx.current_clip_is_combined */ - // RESET_CONTEXT( aafi->ctx ); + void *ComponentAttributeList = aaf_get_propertyValue( Sequence, aaf_get_PropertyIDByName( aafi->aafd, "ComponentAttributeList" ), &AAFTypeID_TaggedValueStrongReferenceVector ); - aafi->ctx.current_track = ctxBackup.current_track; - aafi->ctx.current_clip = audioClip; + if ( ComponentAttributeList ) { + int32_t *rateNum = aaf_get_TaggedValueByName( aafi->aafd, ComponentAttributeList, "_MIXMATCH_RATE_NUM", &AAFTypeID_Int32 ); + int32_t *rateDenom = aaf_get_TaggedValueByName( aafi->aafd, ComponentAttributeList, "_MIXMATCH_RATE_DENOM", &AAFTypeID_Int32 ); - /* retrieve essence */ - parse_MobSlot( aafi, targetMobSlot, &__td ); + if ( rateNum && rateDenom ) { + aafi->ctx.avid_warp_clip_edit_rate = malloc( sizeof(aafRational_t) ); - memcpy( &(aafi->ctx), &ctxBackup, sizeof(struct aafiContext) ); - } - else { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Targeted Mob isn't MasterMob : %ls", aaft_ClassIDToText( aafi->aafd, targetMob->Class->ID ) ); + if ( !aafi->ctx.avid_warp_clip_edit_rate ) { + error( "Out of memory" ); return -1; } + aafi->ctx.avid_warp_clip_edit_rate->numerator = *rateNum; + aafi->ctx.avid_warp_clip_edit_rate->denominator = *rateDenom; + debug( "Got Avid audio warp edit rate : %i/%i", + aafi->ctx.avid_warp_clip_edit_rate->numerator, + aafi->ctx.avid_warp_clip_edit_rate->denominator ); } - else if ( aafUIDCmp( DataDefinition, &AAFDataDef_Picture ) || - aafUIDCmp( DataDefinition, &AAFDataDef_LegacyPicture ) ) - { - - /* - * │ 04382│├──◻ AAFClassID_TimelineMobSlot [slot:2 track:1] (DataDef : AAFDataDef_Picture) - * │ 01939││ └──◻ AAFClassID_Sequence - * │ 03007││ └──◻ AAFClassID_SourceClip - */ - - /* - * │ 04390│└──◻ AAFClassID_TimelineMobSlot [slot:8 track:1] (DataDef : AAFDataDef_LegacyPicture) : Video Mixdown - * │ 03007│ └──◻ AAFClassID_SourceClip - */ - - if ( aafi->Video->Tracks->Items ) { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Current implementation supports only one video clip" ); - return -1; - } - - /* Add the new clip */ - - aafiTimelineItem *item = aafi_newTimelineItem( aafi, aafi->Video->Tracks, AAFI_VIDEO_CLIP ); - - aafiVideoClip *videoClip = item->data; //(aafiVideoClip*)&item->data; - - videoClip->pos = aafi->Video->Tracks->current_pos; - videoClip->len = *length; - - videoClip->essence_offset = *startTime; - + } - /* - * p.49 : To create a SourceReference that refers to a MobSlot within - * the same Mob as the SourceReference, omit the SourceID property. - * - * NOTE: This should not happen here because The "CompositionMob > SourceClip::SourceID" - * should always point to the corresponding "MasterMob", that is a different Mob. - */ - videoClip->masterMobID = sourceID; + uint32_t i = 0; + AAFI_foreach_ObjectInSet( &Component, Components, i, __td ) { + parse_Component( aafi, Component, &__td ); + } - // if ( videoClip->masterMobID == NULL ) { - // videoClip->masterMobID = aaf_get_propertyValue( ParentMob, PID_Mob_MobID, &AAFTypeID_MobIDType ); - // warning( "Missing SourceReference::SourceID, retrieving from parent Mob." ); - // } + free( aafi->ctx.avid_warp_clip_edit_rate ); + aafi->ctx.avid_warp_clip_edit_rate = NULL; + return 0; +} - if ( !aafUIDCmp( aafi->aafd->Header.OperationalPattern, &AAFOPDef_EditProtocol ) || - aafUIDCmp( CurrentUsageCode, &AAFUsage_TopLevel ) ) - { - /* - * NOTE for AAFOPDef_EditProtocol only : - * - * If SourceClip belongs to a TopLevel Mob, we can update position. - * Otherwise, it means we are inside a derivation chain ( ie: TopLevelCompositionMob -> SourceClip -> SubLevel:CompositionMob -> SourceClip ) - * and the clip length is not the good one. In that case, position is updated above. - */ +static int parse_Selector( AAF_Iface *aafi, aafObject *Selector, td *__ptd ) +{ + /* + * The Selector class is a sub-class of the Segment class. + * + * The Selector class provides the value of a single Segment (PID_Selector_Selected) + * while preserving references to unused alternatives (PID_Selector_Alternates) + */ - aafi->Video->Tracks->current_pos += videoClip->len; - } + struct trace_dump __td; + __td_set(__td, __ptd, 1); - aafi->ctx.current_video_clip = videoClip; + aafObject *Selected = aaf_get_propertyValue( Selector, PID_Selector_Selected, &AAFTypeID_SegmentStrongReference ); + if ( !Selected ) { + TRACE_OBJ_ERROR( aafi, Selector, &__td, "Missing Selector::Selected" ); + return -1; + } - if ( aafUIDCmp( targetMob->Class->ID, &AAFClassID_MasterMob ) ) { - if ( targetMobSlot == NULL ) { - /* TODO isn't it already checked above ? */ - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Missing target MobSlot" ); - return -1; - } + TRACE_OBJ( aafi, Selector, &__td ); - DUMP_OBJ( aafi, SourceClip, &__td ); + aafObject *Alternates = aaf_get_propertyValue( Selector, PID_Selector_Alternates, &AAFTypeID_SegmentStrongReferenceVector ); + if ( Alternates ) { + __td.lv++; + TRACE_OBJ_INFO( aafi, Alternates, &__td, "Selector Alternates (dropping)" ); + __td.lv--; + } - /* Only to print trace */ - __td.lv++; - DUMP_OBJ( aafi, targetMob, &__td ); + /* + * ComponentAttributeList is non-standard, used by Avid Media Composer and + * Davinci Resolve to describe a disabled (muted) clip. This way, any unaware + * implementation will parse Selected Object containing a Filler and ignore + * the disabled clip inside Alternates. + */ - // memcpy( &ctxBackup, &(aafi->ctx), sizeof(struct aafiContext) ); - // - // RESET_CONTEXT( aafi->ctx ); + void *ComponentAttributeList = aaf_get_propertyValue( Selector, aaf_get_PropertyIDByName( aafi->aafd, "ComponentAttributeList" ), &AAFTypeID_TaggedValueStrongReferenceVector ); - parse_MobSlot( aafi, targetMobSlot, &__td ); + if ( ComponentAttributeList ) { + int32_t *disabledClip = aaf_get_TaggedValueByName( aafi->aafd, ComponentAttributeList, "_DISABLE_CLIP_FLAG", &AAFTypeID_Int32 ); - // memcpy( &(aafi->ctx), &ctxBackup, sizeof(struct aafiContext) ); + if ( disabledClip ) { + if ( *disabledClip ) { + aafi->ctx.current_clip_is_muted = 1; + } + /* + * When Selector has _DISABLE_CLIP_FLAG, Alternates should point + * to a single Alternates Object containing the disabled clip. + */ + if ( Alternates ) { + return parse_Segment( aafi, Alternates, &__td ); } else { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Targeted mob isn't MasterMob : %ls", aaft_ClassIDToText( aafi->aafd, targetMob->Class->ID ) ); - // parse_CompositionMob( ) - return -1; + return parse_Segment( aafi, Selected, &__td ); } - } } + else { + /* + * without specific software implementation, we stick to Selected Object + * and forget about any Alternates Objects. + */ + return parse_Segment( aafi, Selected, &__td ); + } - /* *** Essence *** */ - - else if ( aafUIDCmp( ParentMob->Class->ID, &AAFClassID_MasterMob ) ) { + return -1; +} - aafMobID_t *masterMobID = aaf_get_propertyValue( ParentMob, PID_Mob_MobID, &AAFTypeID_MobIDType ); - if ( masterMobID == NULL ) { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve parent Mob PID_Mob_MobID" ); - return -1; - } - aafObject *ParentMobSlot = get_Object_Ancestor( aafi, SourceClip, &AAFClassID_MobSlot ); +static int parse_NestedScope( AAF_Iface *aafi, aafObject *NestedScope, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 1); - if ( ParentMobSlot == NULL ) { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve parent MobSlot" ); - return -1; - } - uint32_t *masterMobSlotID = aaf_get_propertyValue( ParentMobSlot, PID_MobSlot_SlotID, &AAFTypeID_UInt32 ); + /* + * NestedScope seems to be only used for video clips in Avid Media Composer. + * Not sure how to handle it... + */ + aafObject *Slot = NULL; + aafObject *Slots = aaf_get_propertyValue( NestedScope, PID_NestedScope_Slots, &AAFTypeID_SegmentStrongReferenceVector ); - uint32_t *essenceChannelNum = aaf_get_propertyValue( ParentMobSlot, PID_MobSlot_PhysicalTrackNumber, &AAFTypeID_UInt32 ); + if ( !Slots ) { + TRACE_OBJ_ERROR( aafi, NestedScope, &__td, "Missing NestedScope::Slots" ); + return -1; + } + TRACE_OBJ( aafi, NestedScope, &__td ); - if ( aafUIDCmp( DataDefinition, &AAFDataDef_Sound ) || - aafUIDCmp( DataDefinition, &AAFDataDef_LegacySound ) ) - { - if ( !aafi->ctx.current_clip ) { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "aafi->ctx.current_clip not set" ); - return -1; - } + uint32_t i = 0; + AAFI_foreach_ObjectInSet( &Slot, Slots, i, __td ) { + parse_Segment( aafi, Slot, &__td ); + } - /* - * Check if this Essence has already been retrieved - */ + return 0; +} - aafiAudioEssence *audioEssence = NULL; - foreachEssence( audioEssence, aafi->Audio->Essences ) { - if ( aafMobIDCmp( audioEssence->sourceMobID, sourceID ) && audioEssence->sourceMobSlotID == (unsigned)*SourceMobSlotID ) { - __td.eob = 1; - DUMP_OBJ_WARNING( aafi, SourceClip, &__td, "Essence already parsed: Linking with %ls", audioEssence->file_name ); - aafi->ctx.current_clip->essencePointerList = aafi_newAudioEssencePointer( aafi, &aafi->ctx.current_clip->essencePointerList, audioEssence, essenceChannelNum ); - return 0; - } - } +static int parse_OperationGroup( AAF_Iface *aafi, aafObject *OpGroup, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 1); - /* new Essence, carry on. */ + if ( !aaf_get_property( OpGroup, PID_OperationGroup_InputSegments ) && + !aaf_get_property( OpGroup, PID_OperationGroup_Parameters ) ) + { + __td.eob = 1; + } - audioEssence = aafi_newAudioEssence( aafi ); - audioEssence->masterMobSlotID = *masterMobSlotID; - audioEssence->masterMobID = masterMobID; - audioEssence->file_name = aaf_get_propertyValue( ParentMob, PID_Mob_Name, &AAFTypeID_String ); + aafObject *ParentMob = aaf_get_ObjectAncestor( OpGroup, &AAFClassID_Mob ); - if ( audioEssence->file_name == NULL ) { - debug( "Missing MasterMob::PID_Mob_Name (essence file name)" ); - } + if ( !ParentMob ) { + TRACE_OBJ_ERROR( aafi, OpGroup, &__td, "Could not retrieve parent Mob" ); + return -1; + } - /* - * p.49 : « To create a SourceReference that refers to a MobSlot within - * the same Mob as the SourceReference, omit the SourceID property. » - */ + if ( !aafUIDCmp( ParentMob->Class->ID, &AAFClassID_CompositionMob ) ) { + TRACE_OBJ_ERROR( aafi, OpGroup, &__td, "OperationGroup is currently supported only in CompositionMob, not in %s", aaft_ClassIDToText( aafi->aafd, ParentMob->Class->ID ) ); + return -1; + } - audioEssence->sourceMobSlotID = *SourceMobSlotID; - audioEssence->sourceMobID = sourceID; - // if ( audioEssence->sourceMobID == NULL ) { - // audioEssence->sourceMobID = aaf_get_propertyValue( ParentMob, PID_Mob_MobID, &AAFTypeID_MobIDType ); - // warning( "Could not retrieve SourceReference::SourceID, retrieving from parent Mob." ); - // } + int rc = 0; - aafi->ctx.current_essence = audioEssence; + aafWeakRef_t *OperationDefWeakRef = aaf_get_propertyValue( OpGroup, PID_OperationGroup_Operation, &AAFTypeID_OperationDefinitionWeakReference ); + if ( !OperationDefWeakRef ) { + TRACE_OBJ_ERROR( aafi, OpGroup, &__td, "Missing OperationGroup::Operation" ); + return -1; + } - DUMP_OBJ( aafi, SourceClip, &__td ); + aafUID_t *OperationIdentification = aaf_get_OperationIdentificationByWeakRef( aafi->aafd, OperationDefWeakRef ); + if ( !OperationIdentification ) { + TRACE_OBJ_ERROR( aafi, OpGroup, &__td, "Could not retrieve OperationIdentification" ); + return -1; + } - aafObject *SourceMob = aaf_get_MobByID( aafi->aafd->Mobs, audioEssence->sourceMobID ); + /* + * We need to check if OperationGroup is a direct child of TopLevelCompositionMob > TimelineMobSlot. + * - If it is, it means that the OperationGroup affect the current Track. + * - If it's not (eg. it's a child of a Sequence), then OperationGroup applies + * to all descendent clips. + * + * NOTE: OperationGroup can be a child of another OperationGroup. So we can't + * just check direct Parent, we need to loop. + */ - if ( SourceMob == NULL ) { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve SourceMob by ID : %ls", aaft_MobIDToText(audioEssence->sourceMobID) ); - return -1; - } + aafObject *OperationGroupParent = OpGroup->Parent; + while ( OperationGroupParent && aafUIDCmp( OperationGroupParent->Class->ID, &AAFClassID_OperationGroup ) ) { + OperationGroupParent = OperationGroupParent->Parent; + } - audioEssence->SourceMob = SourceMob; + if ( !OperationGroupParent ) { + error( "OperationGroup has no parent !" ); + return -1; + } + if ( aafUIDCmp( OperationGroupParent->Class->ID, &AAFClassID_TimelineMobSlot ) && + ParentMob == aafi->ctx.TopLevelCompositionMob ) + { + aafi->ctx.current_opgroup_affect_track = 1; + } else { + aafi->ctx.current_opgroup_affect_track = 0; + } - aafObject *EssenceData = get_EssenceData_By_MobID( aafi, audioEssence->sourceMobID ); - if ( EssenceData ) - __td.ll[__td.lv] = 2; + if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioDissolve ) ) { + if ( !aafUIDCmp( OpGroup->Parent->Class->ID, &AAFClassID_Transition ) ) { + TRACE_OBJ_ERROR( aafi, OpGroup, &__td, "Parent should be AAFClassID_Transition" ); + return -1; + } - parse_SourceMob( aafi, SourceMob, &__td ); + TRACE_OBJ( aafi, OpGroup, &__td ); - __td.ll[__td.lv] = 0; + aafiTransition *Trans = aafi->ctx.current_transition; + /* + * Mono Audio Dissolve (Fade, Cross Fade) + * + * The same parameter (curve/level) is applied to the outgoing fade on first + * clip (if any) and to the incoming fade on second clip (if any). + */ - if ( EssenceData == NULL ) { - /* - * It means essence is not embedded. - */ - // return -1; - } - else { - parse_EssenceData( aafi, EssenceData, &__td ); - } + Trans->flags |= AAFI_TRANS_SINGLE_CURVE; - audioEssence->unique_file_name = build_unique_audiofilename( aafi, audioEssence ); + aafObject *Param = NULL; + aafObject *Parameters = aaf_get_propertyValue( OpGroup, PID_OperationGroup_Parameters, &AAFTypeID_ParameterStrongReferenceVector ); - aafi->ctx.current_clip->essencePointerList = aafi_newAudioEssencePointer( aafi, &aafi->ctx.current_clip->essencePointerList, audioEssence, essenceChannelNum ); + uint32_t i = 0; + AAFI_foreach_ObjectInSet( &Param, Parameters, i, __td ) { + parse_Parameter( aafi, Param, &__td ); } - else if ( aafUIDCmp( DataDefinition, &AAFDataDef_Picture ) || - aafUIDCmp( DataDefinition, &AAFDataDef_LegacyPicture ) ) - { - /* - * │ 04382│├──◻ AAFClassID_TimelineMobSlot [slot:2 track:1] (DataDef : AAFDataDef_Picture) - * │ 01939││ └──◻ AAFClassID_Sequence - * │ 03007││ └──◻ AAFClassID_SourceClip - * │ 03012││ └──◻ AAFClassID_MasterMob (UsageCode: n/a) : sample@29 - * │ 04402││ └──◻ AAFClassID_TimelineMobSlot - * │ 03234││ └──◻ AAFClassID_SourceClip - */ - - /* - * │ 04390│└──◻ AAFClassID_TimelineMobSlot [slot:8 track:1] (DataDef : AAFDataDef_LegacyPicture) : Video Mixdown - * │ 03007│ └──◻ AAFClassID_SourceClip - * │ 03012│ └──◻ AAFClassID_MasterMob (UsageCode: n/a) : 2975854 - PREPARATIFS DISPOSITIF 2 30.Exported.01,Video Mixdown,5 (MetaProps: ConvertFrameRate[0xfff8]) - * │ 04410│ └──◻ AAFClassID_TimelineMobSlot - * │ 03242│ └──◻ AAFClassID_SourceClip - */ - /* Check if this Essence has already been retrieved */ - - // int slotID = MobSlot->Entry->_localKey; - - - // aafObject *Obj = aaf_get_MobByID( aafi->aafd, sourceID ); - // debug( "SourceMobID : %ls", aaft_MobIDToText(sourceID) ); - // debug( "MasterMobID : %ls", aaft_MobIDToText(mobID) ); + /* + * Avid Media Composer doesn't use the standard method to set interpolation. Instead, + * it always sets InterpolationIdentification to Linear, and it sets the actual + * interpolation in both : + * - OperationGroup > ComponentAttributeList > _ATN_AUDIO_DISSOLVE_CURVETYPE + * - OperationGroup > Parameters > AAFClassID_ConstantValue (ParamDef: Curve Type; Type: AAFTypeID_Int32) : 1 + * + * Note: _ATN_AUDIO_DISSOLVE_CURVETYPE was observed since v8.4 (2015), however "Curve Type" was observed since v18.12.7. + * Using _ATN_AUDIO_DISSOLVE_CURVETYPE provides a better support for older Avid MC versions. + */ - if ( !aafi->ctx.current_video_clip ) { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "aafi->ctx.current_video_clip not set" ); - return -1; - } + void *ComponentAttributeList = aaf_get_propertyValue( OpGroup, aaf_get_PropertyIDByName( aafi->aafd, "ComponentAttributeList" ), &AAFTypeID_TaggedValueStrongReferenceVector ); + if ( ComponentAttributeList ) { - aafiVideoEssence *videoEssence = NULL; + int32_t *curveType = aaf_get_TaggedValueByName( aafi->aafd, ComponentAttributeList, "_ATN_AUDIO_DISSOLVE_CURVETYPE", &AAFTypeID_Int32 ); - foreachEssence( videoEssence, aafi->Video->Essences ) { - if ( aafMobIDCmp( videoEssence->sourceMobID, sourceID ) && videoEssence->sourceMobSlotID == (unsigned)*SourceMobSlotID ) { - /* Essence already retrieved */ - aafi->ctx.current_video_clip->Essence = videoEssence; - __td.eob = 1; - DUMP_OBJ_INFO( aafi, SourceClip, &__td, "Essence already parsed: Linking with %ls", videoEssence->file_name ); - return 0; + if ( curveType ) { + switch ( *curveType ) { + case AVID_MEDIA_COMPOSER_CURVE_TYPE_LINEAR: Trans->flags &= ~(AAFI_INTERPOL_MASK); Trans->flags |= AAFI_INTERPOL_LINEAR; break; + case AVID_MEDIA_COMPOSER_CURVE_TYPE_EQUAL_POWER: Trans->flags &= ~(AAFI_INTERPOL_MASK); Trans->flags |= AAFI_INTERPOL_POWER; break; + default: debug( "Unknown Avid Media Composer fade curve: %i", *curveType ); break; } } + } - /* new Essence, carry on. */ + if ( !(Trans->flags & AAFI_INTERPOL_MASK) ) { + debug( "Setting fade interpolation to default Linear" ); + Trans->flags |= AAFI_INTERPOL_LINEAR; + } + aafi_dump_obj( aafi, NULL, &__td, 0, NULL, -1, "" ); + } + else if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_AudioChannelCombiner ) ) { - videoEssence = aafi_newVideoEssence( aafi ); + TRACE_OBJ( aafi, OpGroup, &__td ); - aafi->ctx.current_video_clip->Essence = videoEssence; + aafObject *InputSegment = NULL; + aafObject *InputSegments = aaf_get_propertyValue( OpGroup, PID_OperationGroup_InputSegments, &AAFTypeID_SegmentStrongReferenceVector ); - videoEssence->masterMobSlotID = *masterMobSlotID; - videoEssence->masterMobID = masterMobID; + aafi->ctx.current_clip_is_combined = 1; + aafi->ctx.current_combined_clip_total_channel = InputSegments->Header->_entryCount; + aafi->ctx.current_combined_clip_channel_num = 0; + aafi->ctx.current_combined_clip_forced_length = 0; + if ( resolve_AAF( aafi ) ) { + /* + * This is clearly a violation of the standard (p 57). When Davinci Resolve + * exports multichannel clips, it does not set SourceClip::Length correctly. + * Instead, it's more like some sort of frame-rounded value which doesn't match + * the timeline. However, the correct value is set to OperationGroup::length... + */ + int64_t *length = aaf_get_propertyValue( OpGroup, PID_Component_Length, &AAFTypeID_LengthType ); + aafi->ctx.current_combined_clip_forced_length = (length) ? *length : 0; + } - videoEssence->file_name = aaf_get_propertyValue( ParentMob, PID_Mob_Name, &AAFTypeID_String ); + uint32_t i = 0; + AAFI_foreach_ObjectInSet( &InputSegment, InputSegments, i, __td ) { + parse_Segment( aafi, InputSegment, &__td ); + aafi->ctx.current_combined_clip_channel_num++; + } - if ( videoEssence->file_name == NULL ) { - debug( "Missing MasterMob::PID_Mob_Name (essence file name)" ); - } + aafi_dump_obj( aafi, NULL, &__td, 0, NULL, -1, "" ); - /* - * p.49 : To create a SourceReference that refers to a MobSlot within - * the same Mob as the SourceReference, omit the SourceID property. - */ - videoEssence->sourceMobSlotID = *SourceMobSlotID; - videoEssence->sourceMobID = sourceID; + aafiAudioTrack *current_track = aafi->ctx.current_track; - // if ( audioEssence->sourceMobID == NULL ) { - // audioEssence->sourceMobID = aaf_get_propertyValue( ParentMob, PID_Mob_MobID, &AAFTypeID_MobIDType ); - // warning( "Could not retrieve SourceReference::SourceID, retrieving from parent Mob." ); - // } + aafiTrackFormat_e track_format = AAFI_TRACK_FORMAT_UNKNOWN; + if ( aafi->ctx.current_combined_clip_total_channel == 2 ) { track_format = AAFI_TRACK_FORMAT_STEREO; } + else if ( aafi->ctx.current_combined_clip_total_channel == 6 ) { track_format = AAFI_TRACK_FORMAT_5_1; } + else if ( aafi->ctx.current_combined_clip_total_channel == 8 ) { track_format = AAFI_TRACK_FORMAT_7_1; } + else { + TRACE_OBJ_ERROR( aafi, OpGroup, &__td, "Unknown track format (%u)", aafi->ctx.current_combined_clip_total_channel ); + RESET_CTX__AudioChannelCombiner( aafi->ctx ); + return -1; + } - DUMP_OBJ( aafi, SourceClip, &__td ); + if ( current_track->format != AAFI_TRACK_FORMAT_NOT_SET && + current_track->format != track_format ) + { + TRACE_OBJ_ERROR( aafi, OpGroup, &__td, "Track format (%u) does not match current clip (%u)", current_track->format, track_format ); + RESET_CTX__AudioChannelCombiner( aafi->ctx ); + return -1; + } + current_track->format = track_format; + RESET_CTX__AudioChannelCombiner( aafi->ctx ); + } + else if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioGain ) ) { - aafObject *SourceMob = aaf_get_MobByID( aafi->aafd->Mobs, videoEssence->sourceMobID ); + aafObject *Param = NULL; + aafObject *Parameters = aaf_get_propertyValue( OpGroup, PID_OperationGroup_Parameters, &AAFTypeID_ParameterStrongReferenceVector ); - if ( SourceMob == NULL ) { - DUMP_OBJ_ERROR( aafi, SourceClip, &__td, "Could not retrieve SourceMob by ID : %ls", aaft_MobIDToText(videoEssence->sourceMobID) ); - return -1; - } + if ( !Parameters ) { + TRACE_OBJ_ERROR( aafi, OpGroup, &__td, "Missing OperationGroup::Parameters" ); + rc = -1; goto end; /* we still have to parse InputSegments, so we're not losing any clip */ + } - videoEssence->SourceMob = SourceMob; + TRACE_OBJ( aafi, OpGroup, &__td ); + uint32_t i = 0; + AAFI_foreach_ObjectInSet( &Param, Parameters, i, __td ) { + parse_Parameter( aafi, Param, &__td ); + } + } + else if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioPan ) ) { - aafObject *EssenceData = get_EssenceData_By_MobID( aafi, videoEssence->sourceMobID ); + /* TODO Should Only be Track-based (first Segment of TimelineMobSlot.) */ - if ( EssenceData ) - __td.ll[__td.lv] = 2; + aafObject *Param = NULL; + aafObject *Parameters = aaf_get_propertyValue( OpGroup, PID_OperationGroup_Parameters, &AAFTypeID_ParameterStrongReferenceVector ); - aafi->ctx.current_video_essence = videoEssence; + if ( !Parameters ) { + TRACE_OBJ_ERROR( aafi, OpGroup, &__td, "Missing OperationGroup::Parameters" ); + rc = -1; goto end; /* we still have to parse InputSegments, so we're not losing any clip */ + } - parse_SourceMob( aafi, SourceMob, &__td ); + TRACE_OBJ( aafi, OpGroup, &__td ); - __td.ll[__td.lv] = 0; + uint32_t i = 0; + AAFI_foreach_ObjectInSet( &Param, Parameters, i, __td ) { + parse_Parameter( aafi, Param, &__td ); + } + } + else if ( aafUIDCmp( OperationIdentification, aaf_get_OperationDefIDByName( aafi->aafd, "Audio Warp" )) ) { + aafObject *Param = NULL; + aafObject *Parameters = aaf_get_propertyValue( OpGroup, PID_OperationGroup_Parameters, &AAFTypeID_ParameterStrongReferenceVector ); - if ( EssenceData == NULL ) { - /* - * It means essence is not embedded. - */ - // return -1; - } - else { - parse_EssenceData( aafi, EssenceData, &__td ); - } + if ( !Parameters ) { + TRACE_OBJ_ERROR( aafi, OpGroup, &__td, "Missing OperationGroup::Parameters" ); + rc = -1; goto end; /* we still have to parse InputSegments, so we're not losing any clip */ + } + TRACE_OBJ( aafi, OpGroup, &__td ); - videoEssence->unique_file_name = build_unique_videofilename( aafi, videoEssence ); - - - // aafi_trace_obj( aafi, SourceClip, ANSI_COLOR_MAGENTA ); - - - - // debug( "Master MOB SOURCE CLIP" ); - // - // aafiVideoEssence *videoEssence = aafi_newVideoEssence( aafi ); - // - // aafi->ctx.current_essence = (aafiVideoEssence*)videoEssence; - // - // - // videoEssence->file_name = aaf_get_propertyValue( /*aafi->ctx.*/ParentMob, PID_Mob_Name, &AAFTypeID_String ); - // - // - // videoEssence->masterMobID = aaf_get_propertyValue( /*aafi->ctx.*/ParentMob, PID_Mob_MobID, &AAFTypeID_MobIDType ); - // - // if ( videoEssence->masterMobID == NULL ) { - // aafi_trace_obj( aafi, SourceClip, ANSI_COLOR_RED ); - // error( "Could not retrieve Mob::MobID." ); - // return -1; - // } - // - // /* - // * p.49 : To create a SourceReference that refers to a MobSlot within - // * the same Mob as the SourceReference, omit the SourceID property. - // */ - // - // videoEssence->sourceMobID = SourceID; //aaf_get_propertyValue( SourceClip, PID_SourceReference_SourceID, &AAFTypeID_MobIDType ); - // - // if ( videoEssence->sourceMobID == NULL ) { - // // aafObject *Mob = NULL; - // // - // // for ( Mob = SourceClip; Mob != NULL; Mob = Mob->Parent ) { - // // if ( aafUIDCmp( Mob->Class->ID, &AAFClassID_MasterMob ) ) - // // break; - // // } - // - // videoEssence->sourceMobID = aaf_get_propertyValue( ParentMob, PID_Mob_MobID, &AAFTypeID_MobIDType ); - // - // warning( "Could not retrieve SourceReference::SourceID, retrieving from parent Mob." ); - // } - // - // - // - // aafObject *SourceMob = aaf_get_MobByID( aafi->aafd->Mobs, videoEssence->sourceMobID ); - // - // if ( SourceMob == NULL ) { - // aafi_trace_obj( aafi, SourceClip, ANSI_COLOR_RED ); - // error( "Could not retrieve SourceMob." ); - // return -1; - // } - // - // videoEssence->SourceMob = SourceMob; - // - // - // - // // parse_SourceMob( aafi, SourceMob ); - // - // - // /* TODO the following must be moved to parse_SourceMob() !!! */ - // - // aafObject *EssenceDesc = aaf_get_propertyValue( SourceMob, PID_SourceMob_EssenceDescription, &AAFTypeID_EssenceDescriptorStrongReference ); - // - // if ( EssenceDesc == NULL ) { - // aafi_trace_obj( aafi, SourceClip, ANSI_COLOR_RED ); - // error( "Could not retrieve EssenceDesc." ); - // return -1; - // } - // - // - // // TODO - // parse_EssenceDescriptor( aafi, EssenceDesc ); - // - // - // - // videoEssence->unique_file_name = build_unique_videofilename( aafi, videoEssence ); - // - // - // - // /* NOTE since multiple clips can point to the same MasterMob, we have to loop. */ - // - // aafiVideoTrack * videoTrack = NULL; - // aafiTimelineItem * videoItem = NULL; - // - // foreach_videoTrack( videoTrack, aafi ) { - // foreach_Item( videoItem, videoTrack ) { - // if ( videoItem->type != AAFI_VIDEO_CLIP ) { - // continue; - // } - // - // aafiVideoClip *videoClip = (aafiVideoClip*)&videoItem->data; - // - // if ( aafMobIDCmp( videoClip->masterMobID, videoEssence->masterMobID ) ) { - // debug( "FOUND VIDEO ESSENCE CLIP !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" ); - // videoClip->Essence = videoEssence; - // } - // } - // } - // - // aafi_trace_obj( aafi, SourceClip, ANSI_COLOR_MAGENTA ); - // + uint32_t i = 0; + AAFI_foreach_ObjectInSet( &Param, Parameters, i, __td ) { + parse_Parameter( aafi, Param, &__td ); } } else { - DUMP_OBJ_NO_SUPPORT( aafi, SourceClip, &__td ); - return -1; + /* + * Unknown usage and implementation, not encountered yet: + * + * AAFOperationDef_MonoAudioMixdown + * AAFOperationDef_StereoAudioGain + * AAFOperationDef_TwoParameterMonoAudioDissolve + * AAFOperationDef_StereoAudioDissolve + */ + debug( "Unsupported OperationIdentification: %s", aaft_OperationDefToText( aafi->aafd, OperationIdentification ) ); + TRACE_OBJ_NO_SUPPORT( aafi, OpGroup, &__td ); + + + aafObject *Param = NULL; + aafObject *Parameters = aaf_get_propertyValue( OpGroup, PID_OperationGroup_Parameters, &AAFTypeID_ParameterStrongReferenceVector ); + + if ( !Parameters ) { + // TRACE_OBJ_ERROR( aafi, OpGroup, &__td, "Missing OperationGroup::Parameters" ); + rc = -1; goto end; /* we still have to parse InputSegments, so we're not losing any clip */ + } + + uint32_t i = 0; + AAFI_foreach_ObjectInSet( &Param, Parameters, i, __td ) { + parse_Parameter( aafi, Param, &__td ); + } } - return 0; -} +end: -static int parse_Selector( AAF_Iface *aafi, aafObject *Selector, td *__ptd ) -{ /* - * The Selector class is a sub-class of the Segment class. - * - * The Selector class provides the value of a single Segment (PID_Selector_Selected) - * while preserving references to unused alternatives (PID_Selector_Alternates) + * Parses Segments in the OperationGroup::InputSegments, only if + * OperationGroup is not a Transition as a Transition has no InputSegments, + * and not an AudioChannelCombiner as they were already parsed. */ + if ( !aafUIDCmp( OpGroup->Parent->Class->ID, &AAFClassID_Transition ) && + !aafUIDCmp( OperationIdentification, &AAFOperationDef_AudioChannelCombiner ) ) + { + aafObject *InputSegment = NULL; + aafObject *InputSegments = aaf_get_propertyValue( OpGroup, PID_OperationGroup_InputSegments, &AAFTypeID_SegmentStrongReferenceVector ); - struct trace_dump __td; - __td_set(__td, __ptd, 1); - - - if ( resolve_AAF( aafi ) ) { - return resolve_parse_aafObject_Selector( aafi, Selector, &__td ); + uint32_t i = 0; + AAFI_foreach_ObjectInSet( &InputSegment, InputSegments, i, __td ) { + parse_Segment( aafi, InputSegment, &__td ); + } } - aafObject *Selected = aaf_get_propertyValue( Selector, PID_Selector_Selected, &AAFTypeID_SegmentStrongReference ); + /* End of current OperationGroup context. */ - if ( Selected == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, Selector, &__td, "Missing PID_Selector_Selected" ); - return -1; - } + aafObject *Obj = OpGroup; + for (; Obj != NULL && aafUIDCmp( Obj->Class->ID, &AAFClassID_ContentStorage ) == 0; Obj = Obj->Parent ) + if ( !aafUIDCmp( Obj->Class->ID, &AAFClassID_OperationGroup ) ) + break; - // aafObject *Alternate = NULL; - aafObject *Alternates = aaf_get_propertyValue( Selector, PID_Selector_Alternates, &AAFTypeID_SegmentStrongReferenceVector ); + if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioGain ) ) { - if ( Alternates == NULL ) { /* opt */ - // DUMP_OBJ_WARNING( aafi, Selector, &__td, "Missing PID_Selector_Alternates" ); - } + if ( !aafUIDCmp( Obj->Class->ID, &AAFClassID_TimelineMobSlot ) ) { + if ( aafi->ctx.current_clip_gain_is_used == 0 ) { + aafi_freeAudioGain( aafi->ctx.current_clip_gain ); + } + + if ( aafi->ctx.current_clip_variable_gain_is_used == 0 ) { + aafi_freeAudioGain( aafi->ctx.current_clip_variable_gain ); + } - DUMP_OBJ( aafi, Selector, &__td ); + RESET_CTX__AudioGain( aafi->ctx ); + } + } - /* without specific software implementation we stick to Selected and forget about Alternates */ - return aafi_parse_Segment( aafi, Selected, &__td ); + return rc; } @@ -3496,7 +2162,7 @@ static int parse_Parameter( AAF_Iface *aafi, aafObject *Parameter, td *__ptd ) } else { __td_set(__td, __ptd, 1); - DUMP_OBJ_ERROR( aafi, Parameter, &__td, "Parameter is neither of class Constant nor Varying : %ls", aaft_ClassIDToText(aafi->aafd, Parameter->Class->ID) ); + TRACE_OBJ_ERROR( aafi, Parameter, &__td, "Parameter is neither of class Constant nor Varying : %s", aaft_ClassIDToText(aafi->aafd, Parameter->Class->ID) ); } return -1; @@ -3509,8 +2175,6 @@ static int parse_ConstantValue( AAF_Iface *aafi, aafObject *ConstantValue, td *_ struct trace_dump __td; __td_set(__td, __ptd, 1); - // __td.sub = 1; - if ( !aaf_get_propertyValue( ConstantValue->Parent, PID_OperationGroup_InputSegments, &AAFTypeID_SegmentStrongReferenceVector ) ) { __td.eob = 1; } @@ -3518,140 +2182,147 @@ static int parse_ConstantValue( AAF_Iface *aafi, aafObject *ConstantValue, td *_ aafUID_t *ParamDef = aaf_get_propertyValue( ConstantValue, PID_Parameter_Definition, &AAFTypeID_AUID ); - if ( ParamDef == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, ConstantValue, &__td, "Missing PID_Parameter_Definition" ); + if ( !ParamDef ) { + TRACE_OBJ_ERROR( aafi, ConstantValue, &__td, "Missing Parameter::Definition" ); return -1; } - aafUID_t *OperationIdentification = get_OperationGroup_OperationIdentification( aafi, ConstantValue->Parent ); + aafWeakRef_t *OperationDefWeakRef = aaf_get_propertyValue( ConstantValue->Parent, PID_OperationGroup_Operation, &AAFTypeID_OperationDefinitionWeakReference ); - if ( OperationIdentification == NULL ) { - DUMP_OBJ_ERROR( aafi, ConstantValue, &__td, "Could not retrieve OperationIdentification" ); + if ( !OperationDefWeakRef ) { + TRACE_OBJ_ERROR( aafi, ConstantValue, &__td, "Missing OperationGroup::Operation" ); return -1; } + aafUID_t *OperationIdentification = aaf_get_OperationIdentificationByWeakRef( aafi->aafd, OperationDefWeakRef ); - if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioGain ) && - aafUIDCmp( ParamDef, &AAFParameterDef_Amplitude ) ) - { - aafIndirect_t *Indirect = aaf_get_propertyValue( ConstantValue, PID_ConstantValue_Value, &AAFTypeID_Indirect ); - - if ( Indirect == NULL ) { - DUMP_OBJ_ERROR( aafi, ConstantValue, &__td, "Missing PID_ConstantValue_Value or wrong AAFTypeID" ); - return -1; - } - - aafRational_t *multiplier = aaf_get_indirectValue( aafi->aafd, Indirect, &AAFTypeID_Rational ); + if ( !OperationIdentification ) { + TRACE_OBJ_ERROR( aafi, ConstantValue, &__td, "Could not retrieve OperationIdentification from parent" ); + return -1; + } - if ( multiplier == NULL ) { - DUMP_OBJ_ERROR( aafi, ConstantValue, &__td, "Could not retrieve Indirect value for PID_ConstantValue_Value" ); - return -1; - } + aafIndirect_t *Indirect = aaf_get_propertyValue( ConstantValue, PID_ConstantValue_Value, &AAFTypeID_Indirect ); + if ( !Indirect ) { + TRACE_OBJ_ERROR( aafi, ConstantValue, &__td, "Missing ConstantValue::Value" ); + return -1; + } - aafiAudioGain *Gain = calloc( sizeof(aafiAudioGain), sizeof(unsigned char) ); + aafObject *ParentMob = aaf_get_ObjectAncestor( ConstantValue, &AAFClassID_Mob ); + aafUID_t *mobUsageCode = aaf_get_propertyValue( ParentMob, PID_Mob_UsageCode, &AAFTypeID_UsageType ); - Gain->pts_cnt = 1; - Gain->value = calloc( 1, sizeof(aafRational_t*) ); - Gain->flags |= AAFI_AUDIO_GAIN_CONSTANT; - memcpy( &Gain->value[0], multiplier, sizeof(aafRational_t) ); + if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioGain ) && + aafUIDCmp( ParamDef, &AAFParameterDef_Amplitude ) ) + { + aafRational_t *value = aaf_get_indirectValue( aafi->aafd, Indirect, &AAFTypeID_Rational ); - /* - * Loop through ancestors to find out who is the parent of OperationGroup. - * If it belongs to TimelineMobSlot, that means the Parameter is attached - * to a Track. If it belongs to a Component, the Parameter is attached to - * a clip. - * - * NOTE: We can't just check the Parent since we can have nested OperationGroups - * providing different effects like Pan, Gain, CustomFx.. Therefore looping - * is required. - */ + if ( !value ) { + TRACE_OBJ_ERROR( aafi, ConstantValue, &__td, "Could not retrieve Indirect value for ConstantValue::Value" ); + return -1; + } - aafObject *Obj = ConstantValue->Parent; // Start with the last OperationGroup - for (; Obj != NULL && aafUIDCmp( Obj->Class->ID, &AAFClassID_ContentStorage ) == 0; Obj = Obj->Parent ) - if ( !aafUIDCmp( Obj->Class->ID, &AAFClassID_OperationGroup ) ) - break; + aafiAudioGain *Gain = aafi_newAudioGain( aafi, AAFI_AUDIO_GAIN_CONSTANT, 0, value ); + if ( !Gain ) { + TRACE_OBJ_ERROR( aafi, ConstantValue, &__td, "Could not create new gain" ); + return -1; + } - if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_TimelineMobSlot ) ) { - /* Track-based Gain */ - aafi->ctx.current_track->gain = Gain; + if ( aafUIDCmp( mobUsageCode, &AAFUsage_AdjustedClip ) ) { + /* + * « Some applications support the notion of an adjusted-clip in which an + * effect is applied directly to a clip and applies to all uses of that + * clip, e.g. an audio gain effect. » + * + * Only Avid Media Composer seems to make use of AdjustedClip, in a way that + * it doesn't affect the timeline composition. It looks like any gain applied + * to a source clip (inside a bin), is just audible when playing that clip + * in preview. + * + * Thus, we just ignore it. + */ + debug( "Ignoring AdjustedClip audio level: %i/%i (%+05.1lf dB) ", Gain->value[0].numerator, Gain->value[0].denominator, 20 * log10( aafRationalToDouble( Gain->value[0] ) ) ); + TRACE_OBJ_WARNING( aafi, ConstantValue, &__td, "Ignoring AdjustedClip audio level" ); + aafi_freeAudioGain( Gain ); + } + else if ( aafi->ctx.current_opgroup_affect_track ) { + /* + * Track-based Volume + */ + if ( !aafi->ctx.current_track ) { + TRACE_OBJ_ERROR( aafi, ConstantValue, &__td, "Current track not set, dropping this volume: %i/%i (%+05.1lf dB)", Gain->value[0].numerator, Gain->value[0].denominator, 20 * log10( aafRationalToDouble( Gain->value[0] ) ) ); + aafi_freeAudioGain( Gain ); + return -1; + } + else if ( aafi->ctx.current_track->gain ) { + TRACE_OBJ_ERROR( aafi, ConstantValue, &__td, "Track volume was already set, dropping this one: %i/%i (%+05.1lf dB)", Gain->value[0].numerator, Gain->value[0].denominator, 20 * log10( aafRationalToDouble( Gain->value[0] ) ) ); + aafi_freeAudioGain( Gain ); + return -1; + } + else { + aafi->ctx.current_track->gain = Gain; + TRACE_OBJ( aafi, ConstantValue, &__td ); + } } else { - /* Clip-based Gain */ + /* + * Clip-based Gain + * Gain is saved in context and it will be set to all OperationGroup descendent clips. + */ if ( aafi->ctx.current_clip_gain ) { - - DUMP_OBJ_ERROR( aafi, ConstantValue, &__td, "Clip gain was already set : +%05.1lf dB", 20 * log10( aafRationalToFloat( aafi->ctx.current_clip_gain->value[0] ) ) ); - - // for ( int i = 0; i < aafi->ctx.current_clip_gain->pts_cnt; i++ ) { - // debug( " VaryingValue: _time: %f _value: %f", - // aafRationalToFloat( aafi->ctx.current_clip_gain->time[i] ), - // aafRationalToFloat( aafi->ctx.current_clip_gain->value[i] ) ); - // } - + TRACE_OBJ_ERROR( aafi, ConstantValue, &__td, "Clip gain was already set, dropping this one: %i/%i (%+05.1lf dB)", Gain->value[0].numerator, Gain->value[0].denominator, 20 * log10( aafRationalToDouble( Gain->value[0] ) ) ); aafi_freeAudioGain( Gain ); return -1; } else { aafi->ctx.current_clip_gain = Gain; - aafi->ctx.clips_using_gain = 0; + TRACE_OBJ( aafi, ConstantValue, &__td ); } } - - - DUMP_OBJ( aafi, ConstantValue, &__td ); - } else if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioPan ) && aafUIDCmp( ParamDef, &AAFParameterDef_Pan ) ) { - /* - * Pan automation shall be track-based. If an application has a different - * native representation (e.g., clip-based pan), it shall convert to and - * from its native representation when exporting and importing the composition. - */ - - aafIndirect_t *Indirect = aaf_get_propertyValue( ConstantValue, PID_ConstantValue_Value, &AAFTypeID_Indirect ); + aafRational_t *value = aaf_get_indirectValue( aafi->aafd, Indirect, &AAFTypeID_Rational ); - if ( Indirect == NULL ) { - DUMP_OBJ_ERROR( aafi, ConstantValue, &__td, "Missing PID_ConstantValue_Value or wrong AAFTypeID" ); + if ( !value ) { + TRACE_OBJ_ERROR( aafi, ConstantValue, &__td, "Could not retrieve Indirect value for ConstantValue::Value" ); return -1; } - aafRational_t *multiplier = aaf_get_indirectValue( aafi->aafd, Indirect, &AAFTypeID_Rational ); - - if ( multiplier == NULL ) { - DUMP_OBJ_ERROR( aafi, ConstantValue, &__td, "Could not retrieve Indirect value for PID_ConstantValue_Value" ); + if ( !aafi->ctx.current_opgroup_affect_track ) { + /* + * « Pan automation shall be track-based. If an application has a different + * native representation (e.g., clip-based pan), it shall convert to and + * from its native representation when exporting and importing the composition. » + * + * NOTE: Never encountered clip-based pan AAF. + */ + TRACE_OBJ_ERROR( aafi, ConstantValue, &__td, "Pan shall be track based" ); return -1; } - // if ( multiplier == NULL ) { - // DUMP_OBJ_ERROR( aafi, ConstantValue, &__td, "Missing PID_ConstantValue_Value or wrong AAFTypeID" ); - // return -1; - // } - - - aafiAudioPan *Pan = calloc( sizeof(aafiAudioPan), sizeof(unsigned char) ); - - - Pan->pts_cnt = 1; - Pan->value = calloc( 1, sizeof(aafRational_t*) ); - Pan->flags |= AAFI_AUDIO_GAIN_CONSTANT; + if ( !aafi->ctx.current_track ) { + TRACE_OBJ_ERROR( aafi, ConstantValue, &__td, "Current track not set" ); + return -1; + } - memcpy( &Pan->value[0], multiplier, sizeof(aafRational_t) ); + aafiAudioPan *Pan = aafi_newAudioPan( aafi, AAFI_AUDIO_GAIN_CONSTANT, 0, value ); + if ( !Pan ) { + TRACE_OBJ_ERROR( aafi, ConstantValue, &__td, "Could not create new pan" ); + return -1; + } - /* Pan is Track-based only. */ aafi->ctx.current_track->pan = Pan; - - DUMP_OBJ( aafi, ConstantValue, &__td ); + TRACE_OBJ( aafi, ConstantValue, &__td ); } else { - DUMP_OBJ_NO_SUPPORT( aafi, ConstantValue, &__td ); + TRACE_OBJ_NO_SUPPORT( aafi, ConstantValue, &__td ); } return 0; @@ -3664,8 +2335,6 @@ static int parse_VaryingValue( AAF_Iface *aafi, aafObject *VaryingValue, td *__p struct trace_dump __td; __td_set(__td, __ptd, 1); - // __td.sub = 1; - if ( !aaf_get_propertyValue( VaryingValue->Parent, PID_OperationGroup_InputSegments, &AAFTypeID_SegmentStrongReferenceVector ) ) { __td.eob = 1; } @@ -3673,24 +2342,37 @@ static int parse_VaryingValue( AAF_Iface *aafi, aafObject *VaryingValue, td *__p aafUID_t *ParamDef = aaf_get_propertyValue( VaryingValue, PID_Parameter_Definition, &AAFTypeID_AUID ); - if ( ParamDef == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, VaryingValue, &__td, "Missing PID_Parameter_Definition" ); + if ( !ParamDef ) { + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Missing Parameter::Definition" ); + return -1; + } + + aafWeakRef_t *OperationDefWeakRef = aaf_get_propertyValue( VaryingValue->Parent, PID_OperationGroup_Operation, &AAFTypeID_OperationDefinitionWeakReference ); + + if ( !OperationDefWeakRef ) { + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Missing OperationGroup::Operation" ); return -1; } - aafUID_t *OperationIdentification = get_OperationGroup_OperationIdentification( aafi, VaryingValue->Parent ); + aafUID_t *OperationIdentification = aaf_get_OperationIdentificationByWeakRef( aafi->aafd, OperationDefWeakRef ); - if ( OperationIdentification == NULL ) { - DUMP_OBJ_ERROR( aafi, VaryingValue, &__td, "Could not retrieve OperationIdentification" ); + if ( !OperationIdentification ) { + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Could not retrieve OperationIdentification from parent" ); return -1; } + aafWeakRef_t *InterpolationDefWeakRef = aaf_get_propertyValue( VaryingValue, PID_VaryingValue_Interpolation, &AAFTypeID_InterpolationDefinitionWeakReference ); + + if ( !InterpolationDefWeakRef ) { + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Missing VaryingValue::Interpolation." ); + return -1; + } aafiInterpolation_e interpolation = 0; - aafUID_t *InterpolationIdentification = get_Parameter_InterpolationIdentification( aafi, VaryingValue ); + aafUID_t *InterpolationIdentification = aaf_get_InterpolationIdentificationByWeakRef( aafi->aafd, InterpolationDefWeakRef ); - if ( InterpolationIdentification == NULL ) { - DUMP_OBJ_WARNING( aafi, VaryingValue, &__td, "Could not retrieve InterpolationIdentification: Setting to Linear" ); + if ( !InterpolationIdentification ) { + TRACE_OBJ_WARNING( aafi, VaryingValue, &__td, "Could not retrieve InterpolationIdentification: Falling back to Linear" ); interpolation = AAFI_INTERPOL_LINEAR; } else if ( aafUIDCmp( InterpolationIdentification, &AAFInterpolationDef_None ) ) { @@ -3712,74 +2394,85 @@ static int parse_VaryingValue( AAF_Iface *aafi, aafObject *VaryingValue, td *__p interpolation = AAFI_INTERPOL_LOG; } else { - DUMP_OBJ_WARNING( aafi, VaryingValue, &__td, "Unknown value for InterpolationIdentification: Falling back to Linear" ); + TRACE_OBJ_WARNING( aafi, VaryingValue, &__td, "Unknown InterpolationIdentification value: Falling back to Linear" ); interpolation = AAFI_INTERPOL_LINEAR; } aafObject *Points = aaf_get_propertyValue( VaryingValue, PID_VaryingValue_PointList, &AAFTypeID_ControlPointStrongReferenceVector ); - if ( Points == NULL ) { + if ( !Points ) { /* - * Some files like the ProTools and LogicPro break standard by having no + * Some AAF files from ProTools and LogicPro break standard by having no * PointList entry for AAFOperationDef_MonoAudioGain. */ - - DUMP_OBJ_WARNING( aafi, VaryingValue, &__td, "Missing PID_VaryingValue_PointList or list is empty" ); + TRACE_OBJ_WARNING( aafi, VaryingValue, &__td, "Missing VaryingValue::PointList" ); return -1; } - // if ( aafUIDCmp( VaryingValue->Parent->Parent->Class->ID, &AAFClassID_Transition ) ) if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioDissolve ) && aafUIDCmp( ParamDef, &AAFParameterDef_Level ) ) { aafiTransition *Trans = aafi->ctx.current_transition; - Trans->flags |= interpolation; - Trans->pts_cnt_a = retrieve_ControlPoints( aafi, Points, &(Trans->time_a), &(Trans->value_a) ); - - if ( Trans->pts_cnt_a < 0 ) { - /* In that case, parse_OperationGroup() will set transition to default. */ - DUMP_OBJ_ERROR( aafi, VaryingValue, &__td, "Could not retrieve ControlPoints" ); + if ( !Trans ) { + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Context current_transition not set" ); return -1; } - // for ( int i = 0; i < Trans->pts_cnt_a; i++ ) { - // debug( "time_%i : %i/%i value_%i : %i/%i", i, Trans->time_a[i].numerator, Trans->time_a[i].denominator, i, Trans->value_a[i].numerator, Trans->value_a[i].denominator ); - // } + Trans->flags |= interpolation; + + /* + * OperationGroup *might* contain a Parameter (ParameterDef_Level) specifying + * the fade curve. However, this parameter is optional regarding AAF_EditProtocol + * and there is most likely no implementation that exports custom fade curves. + * Thus, we only retrieve ParameterDef_Level to set interpolation, and we + * always set the fade as defined in AAF_EditProtocol, with only two points : + * + * « ParameterDef_Level (optional; default is a VaryingValue object + * with two control points: Value 0 at time 0, and value 1 at time 1) » + */ - DUMP_OBJ( aafi, VaryingValue, &__td ); + TRACE_OBJ( aafi, VaryingValue, &__td ); } else if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioGain ) && - aafUIDCmp( ParamDef, &AAFParameterDef_Amplitude ) ) + (aafUIDCmp( ParamDef, &AAFParameterDef_Amplitude ) || aafUIDCmp( ParamDef, aaf_get_ParamDefIDByName( aafi->aafd, "AvidControlClipRatio" ) )) ) { - aafiAudioGain *Gain = calloc( sizeof(aafiAudioGain), sizeof(unsigned char) ); + aafiAudioGain *Gain = aafi_newAudioGain( aafi, 0, interpolation, NULL ); + + if ( !Gain ) { + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Could not create new gain" ); + return -1; + } - Gain->flags |= interpolation; - Gain->pts_cnt = retrieve_ControlPoints( aafi, Points, &Gain->time, &Gain->value ); + int pts_cnt = retrieve_ControlPoints( aafi, Points, &Gain->time, &Gain->value ); - if ( Gain->pts_cnt < 0 ) { - DUMP_OBJ_ERROR( aafi, VaryingValue, &__td, "Could not retrieve ControlPoints" ); + if ( pts_cnt < 0 ) { + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Could not retrieve ControlPoints" ); free( Gain ); return -1; } + Gain->pts_cnt = (unsigned int)pts_cnt; + // for ( int i = 0; i < Gain->pts_cnt; i++ ) { // debug( "time_%i : %i/%i value_%i : %i/%i", i, Gain->time[i].numerator, Gain->time[i].denominator, i, Gain->value[i].numerator, Gain->value[i].denominator ); // } - /* If gain has 2 ControlPoints with both the same value, it means - * we have a flat gain curve. So we can assume constant gain here. */ + /* + * If gain has 2 ControlPoints with both the same value, it means + * we have a flat gain curve. So we can assume constant gain here. + */ if ( Gain->pts_cnt == 2 && ( Gain->value[0].numerator == Gain->value[1].numerator ) && ( Gain->value[0].denominator == Gain->value[1].denominator ) ) { - if ( aafRationalToFloat(Gain->value[0]) == 1.0f ) { + if ( aafRationalToDouble(Gain->value[0]) == 1.0f ) { /* - * Skipping any 1:1 gain allows not to miss any other actual gain (eg. Resolve 18.5.AAF) + * Skipping any 1:1 gain allows not to miss any other actual gain (eg. DR_Audio_Levels.aaf, Resolve 18.5.AAF) * │ 02412││ ├──◻ AAFClassID_OperationGroup (OpIdent: AAFOperationDef_MonoAudioGain; Length: 284630) err │ 03839││ │ ├──◻ AAFClassID_VaryingValue : : Value is continuous 1:1 (0db), skipping it. @@ -3794,7 +2487,7 @@ static int parse_VaryingValue( AAF_Iface *aafi, aafObject *VaryingValue, td *__p │ 01342││ │ └──◻ AAFClassID_PCMDescriptor │ 01529││ │ └──◻ AAFClassID_NetworkLocator : file:///C:/Users/user/Desktop/libAAF/test/res/speech-sample.mp3 */ - DUMP_OBJ_ERROR( aafi, VaryingValue, &__td, "Value is continuous 1:1 (0db), skipping it" ); + TRACE_OBJ_INFO( aafi, VaryingValue, &__td, "Value is continuous 1:1 (0db), skipping it." ); aafi_freeAudioGain( Gain ); return -1; } @@ -3805,61 +2498,50 @@ static int parse_VaryingValue( AAF_Iface *aafi, aafObject *VaryingValue, td *__p } - /* - * Loop through ancestors to find out who is the parent of OperationGroup. - * If it belongs to TimelineMobSlot, that means the Parameter is attached - * to a Track. If it belongs to a Component, the Parameter is attached to - * a clip. - * - * NOTE: We can't just check the Parent since we can have nested OperationGroups - * providing different effects like Pan, Gain, CustomFx.. Therefore looping - * is required. - */ - - aafObject *Obj = VaryingValue->Parent; // Start with the last OperationGroup - for (; Obj != NULL && aafUIDCmp( Obj->Class->ID, &AAFClassID_ContentStorage ) == 0; Obj = Obj->Parent ) - if ( !aafUIDCmp( Obj->Class->ID, &AAFClassID_OperationGroup ) ) - break; - - - if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_TimelineMobSlot ) ) { - /* Track-based Gain */ - + if ( aafi->ctx.current_opgroup_affect_track ) { + /* + * Track-based Volume + */ + if ( !aafi->ctx.current_track ) { + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Current track not set, dropping this volume" ); + aafi_freeAudioGain( Gain ); + return -1; + } if ( aafi->ctx.current_track->gain ) { - DUMP_OBJ_ERROR( aafi, VaryingValue, &__td, "Track Gain was already set" ); + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Track volume was already set" ); aafi_freeAudioGain( Gain ); return -1; } else { aafi->ctx.current_track->gain = Gain; - DUMP_OBJ( aafi, VaryingValue, &__td ); + TRACE_OBJ( aafi, VaryingValue, &__td ); } } else { - /* Clip-based Gain */ - + /* + * Clip-based Gain + * Gain is saved in context and it will be set to all OperationGroup descendent clips. + */ if ( Gain->flags & AAFI_AUDIO_GAIN_CONSTANT ) { if ( aafi->ctx.current_clip_gain ) { - DUMP_OBJ_ERROR( aafi, VaryingValue, &__td, "Clip gain was already set" ); + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Clip gain was already set" ); aafi_freeAudioGain( Gain ); return -1; } else { aafi->ctx.current_clip_gain = Gain; - aafi->ctx.clips_using_gain = 0; - DUMP_OBJ( aafi, VaryingValue, &__td ); + TRACE_OBJ( aafi, VaryingValue, &__td ); } } else { - if ( aafi->ctx.current_clip_automation ) { - DUMP_OBJ_ERROR( aafi, VaryingValue, &__td, "Clip automation was already set" ); + if ( aafi->ctx.current_clip_variable_gain ) { + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Clip automation was already set" ); aafi_freeAudioGain( Gain ); return -1; } else { - aafi->ctx.current_clip_automation = Gain; - aafi->ctx.clips_using_automation = 0; - DUMP_OBJ( aafi, VaryingValue, &__td ); + aafi->ctx.current_clip_variable_gain = Gain; + TRACE_OBJ( aafi, VaryingValue, &__td ); } } } @@ -3867,61 +2549,71 @@ static int parse_VaryingValue( AAF_Iface *aafi, aafObject *VaryingValue, td *__p else if ( aafUIDCmp( OperationIdentification, &AAFOperationDef_MonoAudioPan ) && aafUIDCmp( ParamDef, &AAFParameterDef_Pan ) ) { - /* - * Pan automation shall be track-based. If an application has a different - * native representation (e.g., clip-based pan), it shall convert to and - * from its native representation when exporting and importing the composition. - */ - aafiAudioPan *Pan = calloc( sizeof(aafiAudioPan), sizeof(unsigned char) ); + if ( !aafi->ctx.current_opgroup_affect_track ) { + /* + * « Pan automation shall be track-based. If an application has a different + * native representation (e.g., clip-based pan), it shall convert to and + * from its native representation when exporting and importing the composition. » + * + * NOTE: Never encountered clip-based pan AAF. + */ + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Pan shall be track based" ); + return -1; + } + + if ( !aafi->ctx.current_track ) { + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Current track not set" ); + return -1; + } + + if ( aafi->ctx.current_track->pan ) { + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Track Pan was already set" ); + return -1; + } - Pan->flags |= AAFI_AUDIO_GAIN_VARIABLE; - Pan->flags |= interpolation; + aafiAudioPan *Pan = aafi_newAudioPan( aafi, 0, interpolation, NULL ); + + if ( !Pan ) { + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Could not create new pan" ); + return -1; + } - Pan->pts_cnt = retrieve_ControlPoints( aafi, Points, &Pan->time, &Pan->value ); + int pts_cnt = retrieve_ControlPoints( aafi, Points, &Pan->time, &Pan->value ); - if ( Pan->pts_cnt < 0 ) { - DUMP_OBJ_ERROR( aafi, VaryingValue, &__td, "Could not retrieve ControlPoints" ); + if ( pts_cnt < 0 ) { + TRACE_OBJ_ERROR( aafi, VaryingValue, &__td, "Could not retrieve ControlPoints" ); free( Pan ); return -1; } + Pan->pts_cnt = (unsigned int)pts_cnt; + // for ( int i = 0; i < Gain->pts_cnt; i++ ) { // debug( "time_%i : %i/%i value_%i : %i/%i", i, Gain->time[i].numerator, Gain->time[i].denominator, i, Gain->value[i].numerator, Gain->value[i].denominator ); // } - /* If Pan has 2 ControlPoints with both the same value, it means - * we have a constant Pan curve. So we can assume constant Pan here. */ + + /* + * If Pan has 2 ControlPoints with both the same value, it means + * we have a constant Pan curve. So we can assume constant Pan here. + */ if ( Pan->pts_cnt == 2 && ( Pan->value[0].numerator == Pan->value[1].numerator ) && ( Pan->value[0].denominator == Pan->value[1].denominator ) ) { - // if ( aafRationalToFloat(Gain->value[0]) == 1.0f ) { - // /* - // * Pan is null, skip it. Skipping it allows not to set a useless gain then miss the real clip gain later (Resolve 18.5.AAF) - // */ - // aafi_freeAudioGain( Gain ); - // return -1; - // } Pan->flags |= AAFI_AUDIO_GAIN_CONSTANT; } else { Pan->flags |= AAFI_AUDIO_GAIN_VARIABLE; } - if ( aafi->ctx.current_track->pan ) { - DUMP_OBJ_ERROR( aafi, VaryingValue, &__td, "Track Pan was already set" ); - aafi_freeAudioGain( Pan ); - return -1; - } - else { - aafi->ctx.current_track->pan = Pan; - DUMP_OBJ( aafi, VaryingValue, &__td ); - } + aafi->ctx.current_track->pan = Pan; + TRACE_OBJ( aafi, VaryingValue, &__td ); } else { - DUMP_OBJ( aafi, VaryingValue, &__td ); + TRACE_OBJ_NO_SUPPORT( aafi, VaryingValue, &__td ); } return 0; @@ -3929,605 +2621,678 @@ static int parse_VaryingValue( AAF_Iface *aafi, aafObject *VaryingValue, td *__p -static int retrieve_ControlPoints( AAF_Iface *aafi, aafObject *Points, aafRational_t *times[], aafRational_t *values[] ) +/* **************************************************************************** + * E s s e n c e D e s c r i p t o r + * **************************************************************************** + * + * EssenceDescriptor (abs) + * | + * |--> FileDescriptor (abs) + * | | + * | |--> WAVEDescriptor + * | |--> AIFCDescriptor + * | |--> SoundDescriptor + * | | | + * | | `--> PCMDescriptor + * | | + * | `--> DigitalImageDescriptor (abs) + * | | + * | `--> CDCIDescriptor + * | + * | + * |--> PhysicalDescriptor + * `--> TapeDescriptor + */ + +static int parse_EssenceDescriptor( AAF_Iface *aafi, aafObject *EssenceDesc, td *__ptd ) { - *times = calloc( Points->Header->_entryCount, sizeof(aafRational_t) ); - *values = calloc( Points->Header->_entryCount, sizeof(aafRational_t) ); + struct trace_dump __td; + __td_set(__td, __ptd, 1); - aafObject *Point = NULL; + if ( !aaf_get_property( EssenceDesc, PID_EssenceDescriptor_Locator ) ) + __td.eob = 1; - unsigned int i = 0; - aaf_foreach_ObjectInSet( &Point, Points, &AAFClassID_ControlPoint ) { + if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_PCMDescriptor ) ) { + parse_PCMDescriptor( aafi, EssenceDesc, &__td ); + } + else if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_WAVEDescriptor ) ) { + parse_WAVEDescriptor( aafi, EssenceDesc, &__td ); + } + else if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_AIFCDescriptor ) ) { + parse_AIFCDescriptor( aafi, EssenceDesc, &__td ); + } + else if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_SoundDescriptor ) ) { + /* Compressed Audio (MP3, AAC ?). Not encountered yet (Davinci Resolve describes MP3 using PCMDescriptor...) */ + TRACE_OBJ_NO_SUPPORT( aafi, EssenceDesc, &__td ); + } + else if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_AES3PCMDescriptor ) ) { + /* Not described in specs, not encountered yet. */ + TRACE_OBJ_NO_SUPPORT( aafi, EssenceDesc, &__td ); + } + else if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_MultipleDescriptor ) ) { - aafRational_t *time = aaf_get_propertyValue( Point, PID_ControlPoint_Time, &AAFTypeID_Rational ); + /* + * A MultipleDescriptor contains a vector of FileDescriptor objects and is + * used when the file source consists of multiple tracks of essence (e.g MXF). + * Each essence track is described by a MobSlots object in the SourceMob and a + * FileDescriptor object. The FileDescriptor is linked to the MobSlot by + * setting the FileDescriptor::LinkedSlotID property equal to the + * MobSlot::SlotID property. + * + * -> test.aaf + * -> /test/private/thirdparty/2997fps-DFTC.aaf + */ - if ( time == NULL ) { - // aafi_trace_obj( aafi, Points, ANSI_COLOR_RED ); - error( "Missing ControlPoint::Time." ); + TRACE_OBJ_NO_SUPPORT( aafi, EssenceDesc, &__td ); + } + else if ( aafUIDCmp( EssenceDesc->Class->ID, &AAFClassID_CDCIDescriptor ) ) { + parse_CDCIDescriptor( aafi, EssenceDesc, &__td ); + } + else { + TRACE_OBJ_NO_SUPPORT( aafi, EssenceDesc, &__td ); + } - free( *times ); *times = NULL; - free( *values ); *values = NULL; - return -1; - } + /* + * Locators are a property of EssenceDescriptor. The property holds a vector of + * Locators object, that should provide information to help find a file that + * contains the essence (WAV, MXF, etc.) or to help find the physical media. + * + * A Locator can either be a NetworkLocator or a TextLocator. + * + * A NetworkLocator holds a URLString property : + * + * p.41 : Absolute Uniform Resource Locator (URL) complying with RFC 1738 or relative + * Uniform Resource Identifier (URI) complying with RFC 2396 for file containing + * the essence. If it is a relative URI, the base URI is determined from the URI + * of the AAF file itself. + * Informative note: A valid URL or URI uses a constrained character set and uses + * the / character as the path separator. + */ + aafObject *Locator = NULL; + aafObject *Locators = aaf_get_propertyValue( EssenceDesc, PID_EssenceDescriptor_Locator, &AAFTypeID_LocatorStrongReferenceVector ); - // aafRational_t *value = aaf_get_propertyIndirectValue( Point, PID_ControlPoint_Value, &AAFTypeID_Rational ); + uint32_t i = 0; + AAFI_foreach_ObjectInSet( &Locator, Locators, i, __td ) { + /* TODO retrieve all locators, then when searching file, try all parsed locators. */ + parse_Locator( aafi, Locator, &__td ); + } - aafIndirect_t *Indirect = aaf_get_propertyValue( Point, PID_ControlPoint_Value, &AAFTypeID_Indirect ); - if ( Indirect == NULL ) { - // DUMP_OBJ_ERROR( aafi, ConstantValue, &__td, "Missing PID_ConstantValue_Value or wrong AAFTypeID" ); - error( "Missing ControlPoint::Value or wrong AAFTypeID" ); + return 0; +} - free( *times ); *times = NULL; - free( *values ); *values = NULL; - return -1; - } - aafRational_t *value = aaf_get_indirectValue( aafi->aafd, Indirect, &AAFTypeID_Rational ); +static int parse_PCMDescriptor( AAF_Iface *aafi, aafObject *PCMDescriptor, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 0); - if ( value == NULL ) { - // aafi_trace_obj( aafi, Points, ANSI_COLOR_RED ); - error( "Could not retrieve Indirect value for PID_ControlPoint_Value" ); - free( *times ); *times = NULL; - free( *values ); *values = NULL; + aafiAudioEssenceFile *audioEssenceFile = (aafiAudioEssenceFile*)aafi->ctx.current_audio_essence; - return -1; - } + if ( !audioEssenceFile ) { + TRACE_OBJ_ERROR( aafi, PCMDescriptor, &__td, "aafi->ctx.current_audio_essence not set" ); + return -1; + } - memcpy( (*times+i), time, sizeof(aafRational_t) ); - memcpy( (*values+i), value, sizeof(aafRational_t) ); + audioEssenceFile->type = AAFI_ESSENCE_TYPE_PCM; - i++; - } - if ( Points->Header->_entryCount != i ) { - // aafi_trace_obj( aafi, Points, ANSI_COLOR_YELLOW ); - warning( "Points _entryCount (%i) does not match iteration (%i).", Points->Header->_entryCount, i ); - return i; + /* Duration of the essence in sample units (not edit units !) */ + aafPosition_t *length = aaf_get_propertyValue( PCMDescriptor, PID_FileDescriptor_Length, &AAFTypeID_PositionType ); + + if ( !length ) { + TRACE_OBJ_ERROR( aafi, PCMDescriptor, &__td, "Missing FileDescriptor::Length" ); + return -1; } + audioEssenceFile->length = *length; - // aafi_trace_obj( aafi, Points, ANSI_COLOR_MAGENTA ); - return Points->Header->_entryCount; -} + uint32_t *channels = aaf_get_propertyValue( PCMDescriptor, PID_SoundDescriptor_Channels, &AAFTypeID_UInt32 ); + if ( !channels ) { + TRACE_OBJ_ERROR( aafi, PCMDescriptor, &__td, "Missing SoundDescriptor::Channels" ); + return -1; + } -/* **************************************************************************** - * M o b - * **************************************************************************** + if ( *channels >= USHRT_MAX ) { + TRACE_OBJ_ERROR( aafi, PCMDescriptor, &__td, "SoundDescriptor::Channels bigger than USHRT_MAX" ); + return -1; + } - * Mob (abs) - * | - * |--> CompositionMob - * |--> MasterMob - * `--> SourceMob - */ + audioEssenceFile->channels = *(uint16_t*)channels; -static int parse_Mob( AAF_Iface *aafi, aafObject *Mob ) -{ - // int dl = DUMP_INIT(aafi); - // __td(NULL); - static td __td; - __td.fn = __LINE__; - __td.pfn = 0; - __td.lv = 0; - __td.ll = calloc( 1024, sizeof(int) ); /* TODO free */ - __td.ll[0] = 0; - // aafi->ctx.trace_leveloop = __td.ll; // keep track of __td.ll for free - int rc = 0; + aafRational_t *samplerate = aaf_get_propertyValue( PCMDescriptor, PID_FileDescriptor_SampleRate, &AAFTypeID_Rational ); - aafObject *MobSlots = aaf_get_propertyValue( Mob, PID_Mob_Slots, &AAFTypeID_MobSlotStrongReferenceVector ); + if ( !samplerate ) { + TRACE_OBJ_ERROR( aafi, PCMDescriptor, &__td, "Missing FileDescriptor::SampleRate" ); + return -1; + } - if ( MobSlots == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, Mob, &__td, "Missing PID_Mob_Slots" ); - goto err; + if ( samplerate->denominator != 1 ) { + TRACE_OBJ_ERROR( aafi, PCMDescriptor, &__td, "FileDescriptor::SampleRate should be integer but is %i/%i", samplerate->numerator, samplerate->denominator ); + return -1; } + if ( samplerate-> numerator < 0 ) { + TRACE_OBJ_ERROR( aafi, PCMDescriptor, &__td, "FileDescriptor::SampleRate value is invalid : %i", samplerate->numerator ); + return -1; + } - if ( aafUIDCmp( Mob->Class->ID, &AAFClassID_CompositionMob ) ) { + audioEssenceFile->samplerate = (uint32_t)samplerate->numerator; - aafUID_t *UsageCode = aaf_get_propertyValue( Mob, PID_Mob_UsageCode, &AAFTypeID_UsageType ); + audioEssenceFile->samplerateRational->numerator = samplerate->numerator; + audioEssenceFile->samplerateRational->denominator = samplerate->denominator; - if ( aafUIDCmp( UsageCode, &AAFUsage_AdjustedClip ) ) { - DUMP_OBJ_ERROR( aafi, Mob, &__td, "Skipping AAFUsage_AdjustedClip" ); - goto err; - } - parse_CompositionMob( aafi, Mob, &__td ); + + uint32_t *samplesize = aaf_get_propertyValue( PCMDescriptor, PID_SoundDescriptor_QuantizationBits, &AAFTypeID_UInt32 ); + + if ( !samplesize ) { + TRACE_OBJ_ERROR( aafi, PCMDescriptor, &__td, "Missing SoundDescriptor::QuantizationBits" ); + return -1; } - else if ( aafUIDCmp( Mob->Class->ID, &AAFClassID_MasterMob ) ) { - DUMP_OBJ( aafi, Mob, &__td ); + + if ( *samplesize >= USHRT_MAX ) { + TRACE_OBJ_ERROR( aafi, PCMDescriptor, &__td, "SoundDescriptor::QuantizationBits bigger than USHRT_MAX : %u", samplesize ); + return -1; } - else if ( aafUIDCmp( Mob->Class->ID, &AAFClassID_SourceMob ) ) { - DUMP_OBJ( aafi, Mob, &__td ); + + TRACE_OBJ( aafi, PCMDescriptor, &__td ); + + audioEssenceFile->samplesize = *(uint16_t*)samplesize; + + return 0; +} + + + +static int parse_WAVEDescriptor( AAF_Iface *aafi, aafObject *WAVEDescriptor, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 0); + + + aafiAudioEssenceFile *audioEssenceFile = (aafiAudioEssenceFile*)aafi->ctx.current_audio_essence; + + if ( !audioEssenceFile ) { + TRACE_OBJ_ERROR( aafi, WAVEDescriptor, &__td, "aafi->ctx.current_audio_essence not set" ); + return -1; } + audioEssenceFile->type = AAFI_ESSENCE_TYPE_WAVE; + + + + aafProperty *summary = aaf_get_property( WAVEDescriptor, PID_WAVEDescriptor_Summary ); + + if ( !summary ) { + TRACE_OBJ_ERROR( aafi, WAVEDescriptor, &__td, "Missing WAVEDescriptor::Summary" ); + return -1; + } + + audioEssenceFile->summary = summary; + /* - * Loops through MobSlots + * NOTE : Summary is parsed later in "post-processing" aafi_retrieveData(), + * to be sure clips and essences are linked, so we are able to fallback on + * essence stream in case summary does not contain the full header part. + * + * TODO parse it here */ - aafObject *MobSlot = NULL; + TRACE_OBJ( aafi, WAVEDescriptor, &__td ); - int i = 0; - aaf_foreach_ObjectInSet( &MobSlot, MobSlots, NULL ) { - __td.ll[__td.lv] = MobSlots->Header->_entryCount - i++; - parse_MobSlot( aafi, MobSlot, &__td ); + return 0; +} + + + +static int parse_AIFCDescriptor( AAF_Iface *aafi, aafObject *AIFCDescriptor, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 0); + + + aafiAudioEssenceFile *audioEssenceFile = (aafiAudioEssenceFile*)aafi->ctx.current_audio_essence; + + if ( !audioEssenceFile ) { + TRACE_OBJ_ERROR( aafi, AIFCDescriptor, &__td, "aafi->ctx.current_audio_essence not set" ); + return -1; } - goto end; -err: - rc = -1; + audioEssenceFile->type = AAFI_ESSENCE_TYPE_AIFC; + + + + aafProperty *summary = aaf_get_property( AIFCDescriptor, PID_AIFCDescriptor_Summary ); + + if ( !summary ) { + TRACE_OBJ_ERROR( aafi, AIFCDescriptor, &__td, "Missing AIFCDescriptor::Summary" ); + return -1; + } + + audioEssenceFile->summary = summary; + + + /* + * NOTE : Summary is parsed later in "post-processing" aafi_retrieveData(), + * to be sure clips and essences are linked, so we are able to fallback on + * essence stream in case summary does not contain the full header part. + */ + + TRACE_OBJ( aafi, AIFCDescriptor, &__td ); -end: - free( __td.ll ); - return rc; + return 0; } -static int parse_CompositionMob( AAF_Iface *aafi, aafObject *CompoMob, td *__ptd ) +static int parse_DigitalImageDescriptor( AAF_Iface *aafi, aafObject *DIDescriptor, td *__ptd ) { - struct trace_dump __td; - __td_set( __td, __ptd, 0); + __td_set(__td, __ptd, 0); - DUMP_OBJ( aafi, CompoMob, &__td ); + /* TODO parse and save content to videoEssenceFile */ + aafiVideoEssence *videoEssenceFile = aafi->ctx.current_video_essence; - aafi->compositionName = aaf_get_propertyValue( CompoMob, PID_Mob_Name, &AAFTypeID_String ); /* opt */ + if ( !videoEssenceFile ) { + TRACE_OBJ_ERROR( aafi, DIDescriptor, &__td, "aafi->ctx.current_video_essence not set" ); + return -1; + } + /* + * « Informative note: In the case of picture essence, the Sample Rate is usually the frame rate. The value should be + * numerically exact, for example {25,1} or {30000, 1001}. » + * + * « Informative note: Care should be taken if a sample rate of {2997,100} is encountered, since this may have been intended + * as a (mistaken) approximation to the exact value. » + */ + aafRational_t *framerate = aaf_get_propertyValue( DIDescriptor, PID_FileDescriptor_SampleRate, &AAFTypeID_Rational ); + if ( !framerate ) { + TRACE_OBJ_ERROR( aafi, DIDescriptor, &__td, "Missing FileDescriptor::SampleRate (framerate)" ); + return -1; + } - aafObject *UserComment = NULL; - aafObject *UserComments = aaf_get_propertyValue( CompoMob, PID_Mob_UserComments, &AAFTypeID_TaggedValueStrongReferenceVector ); /* opt */ + videoEssenceFile->framerate = framerate; - aaf_foreach_ObjectInSet( &UserComment, UserComments, NULL ) { + debug( "Video framerate : %i/%i", framerate->numerator, framerate->denominator ); - /* TODO: implement retrieve_TaggedValue() ? */ - wchar_t *name = aaf_get_propertyValue( UserComment, PID_TaggedValue_Name, &AAFTypeID_String ); + /* + * All mandatory properties below are treated as optional, because we assume that + * video will be an external file so we are not using those, and because some AAF + * implementations does not even set those mandatory properties (eg. Davinci Resolve). + * + * TODO: parse PID_FileDescriptor_Length ? + */ - if ( name == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, UserComment, &__td, "Missing PID_TaggedValue_Name" ); - continue; - } + return 0; +} - aafIndirect_t *Indirect = aaf_get_propertyValue( UserComment, PID_TaggedValue_Value, &AAFTypeID_Indirect ); - if ( Indirect == NULL ) { - DUMP_OBJ_ERROR( aafi, UserComment, &__td, "Missing PID_TaggedValue_Value" ); - continue; - } - wchar_t *text = aaf_get_indirectValue( aafi->aafd, Indirect, &AAFTypeID_String ); +static int parse_CDCIDescriptor( AAF_Iface *aafi, aafObject *CDCIDescriptor, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 0); - if ( text == NULL ) { - DUMP_OBJ_ERROR( aafi, UserComment, &__td, "Could not retrieve Indirect value for PID_TaggedValue_Value" ); - continue; - } - aafiUserComment *Comment = aafi_newUserComment( aafi, &aafi->Comments ); + /* TODO parse CDCI class */ - Comment->name = name; - Comment->text = text; - } + int rc = parse_DigitalImageDescriptor( aafi, CDCIDescriptor, __ptd ); + + if ( !rc ) + TRACE_OBJ( aafi, CDCIDescriptor, &__td ); - return 0; + return rc; } -static int parse_SourceMob( AAF_Iface *aafi, aafObject *SourceMob, td *__ptd ) +/* + * Locator (abs) + * | + * ,---------------. + * | | + * NetworkLocator TextLocator + */ + +static int parse_Locator( AAF_Iface *aafi, aafObject *Locator, td *__ptd ) { struct trace_dump __td; __td_set(__td, __ptd, 1); + __td.eob = 1; - __td.hc = 1; + if ( aafUIDCmp( Locator->Class->ID, &AAFClassID_NetworkLocator ) ) { + parse_NetworkLocator( aafi, Locator, &__td ); + } + else if ( aafUIDCmp( Locator->Class->ID, &AAFClassID_TextLocator ) ) { - /* TODO find a better way to check if we're parsing audio */ + /* + * A TextLocator object provides information to the user to help locate the file + * containing the essence or to locate the physical media. The TextLocator is not + * intended for applications to use without user intervention. + * + * Not encountered yet. + */ - // aafUID_t *DataDefinition = get_Component_DataDefinition( aafi, SourceMob ); - // - // if ( DataDefinition == NULL ) /* req */ { - // error( "Could not retrieve MobSlot::Segment DataDefinition." ); - // return -1; - // } - // - // - // - // if ( aafUIDCmp( DataDefinition, &AAFDataDef_Sound ) || - // aafUIDCmp( DataDefinition, &AAFDataDef_LegacySound ) ) + TRACE_OBJ_NO_SUPPORT( aafi, Locator, &__td ); + char *name = aaf_get_propertyValue( Locator, PID_TextLocator_Name, &AAFTypeID_String ); + debug( "Got an AAFClassID_TextLocator : \"%s\"", name ); + free( name ); + } + else { + TRACE_OBJ_NO_SUPPORT( aafi, Locator, &__td ); + } - if ( aafi->ctx.current_essence ) { - if ( aafi->ctx.current_essence == NULL ) { - DUMP_OBJ_ERROR( aafi, SourceMob, &__td, "ctx->current_essence no set" ); - return -1; - } + return 0; +} - aafiAudioEssence *audioEssence = (aafiAudioEssence*)aafi->ctx.current_essence; - aafMobID_t *MobID = aaf_get_propertyValue( SourceMob, PID_Mob_MobID, &AAFTypeID_MobIDType ); +static int parse_NetworkLocator( AAF_Iface *aafi, aafObject *NetworkLocator, td *__ptd ) +{ + struct trace_dump __td; + __td_set(__td, __ptd, 0); - if ( MobID == NULL ) { - DUMP_OBJ_ERROR( aafi, SourceMob, &__td, "Missing PID_Mob_MobID" ); - return -1; - } + /* + * This holds an URI pointing to the essence file, when it is not embedded. + * However, sometimes it holds an URI to the AAF file itself when essence is + * embedded so it's not a reliable way to guess if essence is embedded or not. + */ - memcpy( audioEssence->umid, MobID, sizeof(aafMobID_t) ); + char *original_file_path = aaf_get_propertyValue( NetworkLocator, PID_NetworkLocator_URLString, &AAFTypeID_String ); + if ( original_file_path == NULL ) { + TRACE_OBJ_ERROR( aafi, NetworkLocator, &__td, "Missing NetworkLocator::URLString" ); + goto err; + } - aafTimeStamp_t *CreationTime = aaf_get_propertyValue( SourceMob, PID_Mob_CreationTime, &AAFTypeID_TimeStamp ); - if ( CreationTime == NULL ) { - DUMP_OBJ_ERROR( aafi, SourceMob, &__td, "Missing PID_Mob_CreationTime" ); - return -1; + if ( aafi->ctx.current_audio_essence ) { + if ( aafi->ctx.current_audio_essence->original_file_path ) { + TRACE_OBJ_ERROR( aafi, NetworkLocator, &__td, "File path was already set" ); + goto err; + } + else { + aafi->ctx.current_audio_essence->original_file_path = original_file_path; } - - snprintf( audioEssence->originationDate, sizeof(audioEssence->originationDate), "%04u:%02u:%02u", - (CreationTime->date.year <= 9999) ? CreationTime->date.year : 0, - (CreationTime->date.month <= 99) ? CreationTime->date.month : 0, - (CreationTime->date.day <= 99) ? CreationTime->date.day : 0 ); - - snprintf( audioEssence->originationTime, sizeof(audioEssence->originationTime), "%02u:%02u:%02u", - (CreationTime->time.hour <= 99) ? CreationTime->time.hour : 0, - (CreationTime->time.minute <= 99) ? CreationTime->time.minute : 0, - (CreationTime->time.second <= 99) ? CreationTime->time.second : 0 ); - } - - - aafObject *EssenceDesc = aaf_get_propertyValue( SourceMob, PID_SourceMob_EssenceDescription, &AAFTypeID_EssenceDescriptorStrongReference ); - - if ( EssenceDesc == NULL ) { - DUMP_OBJ_ERROR( aafi, SourceMob, &__td, "Could not retrieve EssenceDescription" ); - return -1; + else if ( aafi->ctx.current_video_essence ) { + if ( aafi->ctx.current_video_essence->original_file_path ) { + TRACE_OBJ_ERROR( aafi, NetworkLocator, &__td, "File path was already set" ); + goto err; + } + else { + aafi->ctx.current_video_essence->original_file_path = original_file_path; + } + } + else { + TRACE_OBJ_ERROR( aafi, NetworkLocator, &__td, "No current essence set" ); + goto err; } - DUMP_OBJ( aafi, SourceMob, &__td ); + TRACE_OBJ( aafi, NetworkLocator, &__td ); + return 0; - parse_EssenceDescriptor( aafi, EssenceDesc, &__td ); +err: + free( original_file_path ); - return 0; + return -1; } -static aafiAudioTrack * get_audio_track_by_tracknumber( AAF_Iface *aafi, int tracknumber ) +static int parse_EssenceData( AAF_Iface *aafi, aafObject *EssenceData, td *__ptd ) { - aafiAudioTrack *audioTrack = NULL; - int count = 0; - - foreach_audioTrack( audioTrack, aafi ) { - if ( ++count == tracknumber ) - return audioTrack; - } + struct trace_dump __td; + __td_set(__td, __ptd, 1); + __td.eob = 1; - return NULL; -} + int rc = 0; -/* **************************************************************************** - * M o b S l o t - * **************************************************************************** - * - * MobSlot (abs) - * | - * |--> TimelineMobSlot - * |--> EventMobSlot - * `--> StaticMobSlot - */ + char *streamName = NULL; + char *dataPath = NULL; -static int parse_MobSlot( AAF_Iface *aafi, aafObject *MobSlot, td *__ptd ) -{ - // debug( "MS : %p", __ptd->ll ); - struct trace_dump __td; - __td_set(__td, __ptd, 1); + aafiAudioEssenceFile *audioEssenceFile = (aafiAudioEssenceFile*)aafi->ctx.current_audio_essence; - __td.hc = 1; + if ( !audioEssenceFile ) { + TRACE_OBJ_ERROR( aafi, EssenceData, &__td, "aafi->ctx.current_audio_essence not set" ); + return -1; + } + streamName = aaf_get_propertyValue( EssenceData, PID_EssenceData_Data, &AAFTypeID_String ); + if ( !streamName ) { + TRACE_OBJ_ERROR( aafi, EssenceData, &__td, "Missing EssenceData::Data" ); + goto err; + } - aafObject *Segment = aaf_get_propertyValue( MobSlot, PID_MobSlot_Segment, &AAFTypeID_SegmentStrongReference ); + char *path = aaf_get_ObjectPath( EssenceData ); - if ( Segment == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, MobSlot, &__td, "Missing PID_MobSlot_Segment" ); - return -1; + if ( !path ) { + TRACE_OBJ_ERROR( aafi, EssenceData, &__td, "Could not retrieve EssenceData node path" ); + goto err; } + dataPath = laaf_util_build_path( AAF_DIR_SEP_STR, path, streamName, NULL ); + + if ( !dataPath ) { + TRACE_OBJ_ERROR( aafi, EssenceData, &__td, "Could not build Data stream path" ); + goto err; + } - aafUID_t *DataDefinition = get_Component_DataDefinition( aafi, Segment ); + cfbNode *DataNode = cfb_getNodeByPath( aafi->aafd->cfbd, dataPath, 0 ); - if ( DataDefinition == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, MobSlot, &__td, "Could not retrieve DataDefinition" ); - return -1; + if ( !DataNode ) { + TRACE_OBJ_ERROR( aafi, EssenceData, &__td, "Could not retrieve Data stream node: %s", dataPath ); + goto err; } + TRACE_OBJ( aafi, EssenceData, &__td ); - if ( aafUIDCmp( MobSlot->Class->ID, &AAFClassID_TimelineMobSlot ) ) { + debug( "Embedded data stream : %s", dataPath ); - /* - * Each TimelineMobSlot represents a track, either audio or video. - * - * The Timeline MobSlot::Segment should hold a Sequence of Components. - * This Sequence represents the timeline track. Therefore, each SourceClip - * contained in the Sequence::Components represents a clip on the timeline. - * - * CompositionMob can have TimelineMobSlots, StaticMobSlots, EventMobSlots - */ - aafRational_t *edit_rate = aaf_get_propertyValue( MobSlot, PID_TimelineMobSlot_EditRate, &AAFTypeID_Rational ); + audioEssenceFile->node = DataNode; + audioEssenceFile->is_embedded = 1; - if ( edit_rate == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, MobSlot, &__td, "Missing PID_TimelineMobSlot_EditRate" ); - return -1; - } + rc = 0; - if ( aafUIDCmp( /*aafi->ctx.*/MobSlot->Parent->Class->ID, &AAFClassID_CompositionMob ) ) { + goto end; - /* - * There should be only one Composition, since a CompositionMob represents the overall - * composition (i.e project). Observations on files confirm that. - * - * However, the AAF Edit Protocol says that there could be multiple CompositionMobs - * (Mob::UsageCode TopLevel), containing other CompositionMobs (Mob::UsageCode LowerLevel). - * This was not encountered yet, even on Avid exports with AAF_EditProtocol enabled. - * - * TODO: update note - * TODO: implement multiple TopLevel compositions support - */ +err: + rc = -1; - if ( aafUIDCmp( DataDefinition, &AAFDataDef_Sound ) || - aafUIDCmp( DataDefinition, &AAFDataDef_LegacySound ) ) - { +end: - /* - * p.11 : In a CompositionMob or MasterMob, PhysicalTrackNumber is the - * output channel number that the MobSlot should be routed to when played. - */ + free( streamName ); + free( dataPath ); - if ( !aafi->ctx.is_inside_derivation_chain ) { - uint32_t tracknumber = 0; - uint32_t *track_num = aaf_get_propertyValue( MobSlot, PID_MobSlot_PhysicalTrackNumber, &AAFTypeID_UInt32 ); + return rc; +} - if ( track_num == NULL ) { /* opt */ - tracknumber = aafi->Audio->track_count + 1; - } else { - tracknumber = *track_num; - } - aafiAudioTrack *track = get_audio_track_by_tracknumber( aafi, tracknumber ); - if ( !track ) { - track = aafi_newAudioTrack( aafi ); - } - track->number = tracknumber; - aafi->Audio->track_count += 1; +static int retrieve_UserComments( AAF_Iface *aafi, aafObject *UserComments, aafiMetaData **metadataList ) +{ + aafObject *UserComment = NULL; - aafi->ctx.current_track = track; + int error = 0; + AAF_foreach_ObjectInSet( &UserComment, UserComments, NULL ) { + char *text = NULL; + char *name = NULL; - track->name = aaf_get_propertyValue( MobSlot, PID_MobSlot_SlotName, &AAFTypeID_String ); + if ( !aafUIDCmp( UserComment->Class->ID, &AAFClassID_TaggedValue ) ) { + warning( "Parsing UserComments: Expected TaggedValue but got %s", aaft_ClassIDToText( aafi->aafd, UserComment->Class->ID ) ); + goto UserCommentError; + } - track->edit_rate = edit_rate; - } + name = aaf_get_propertyValue( UserComment, PID_TaggedValue_Name, &AAFTypeID_String ); - // aaf_dump_ObjectProperties( aafi->aafd, MobSlot ); + if ( !name ) { + warning( "Parsing UserComments: Missing TaggedValue::Name" ); + goto UserCommentError; + } + aafIndirect_t *Indirect = aaf_get_propertyValue( UserComment, PID_TaggedValue_Value, &AAFTypeID_Indirect ); - /* - * The following seems to be ProTools proprietary. - * If a track is multi-channel, it specifies its format : 2 (stereo), 6 (5.1) or 8 (7.1). - * - * In the current implementation we don't need this. We guess the format at the OperationGroup level with the - * AAFOperationDef_AudioChannelCombiner OperationDefinition, which also looks to be ProTools specific. - */ + if ( !Indirect ) { + warning( "Parsing UserComments: Missing TaggedValue::Value" ); + goto UserCommentError; + } - // aafPID_t PIDTimelineMobAttributeList = aaf_get_PropertyIDByName( aafi->aafd, "TimelineMobAttributeList" ); - // // aafPID_t PIDTimelineMobAttributeList = aaf_get_PropertyIDByName( aafi->aafd, "MobAttributeList" ); - // - // if ( PIDTimelineMobAttributeList != 0 ) { - // aafObject *TaggedValues = aaf_get_propertyValue( aafi->ctx.MobSlot, PIDTimelineMobAttributeList ); - // aafObject *TaggedValue = NULL; - // - // aaf_foreach_ObjectInSet( &TaggedValue, TaggedValues, NULL ) { - // char *name = aaf_get_propertyValueText( TaggedValue, PID_TaggedValue_Name ); - // - // debug( "TaggedValue %s", name ); - // - // if ( strncmp( "_TRACK_FORMAT", name, 13 ) == 0 ) { - // uint32_t *format = (uint32_t*)aaf_get_propertyIndirectValue( TaggedValue, PID_TaggedValue_Value ); - // - // if ( format != NULL ) - // aafi->ctx.current_track->format = *format; - // - // debug( "Format : %u", aafi->ctx.current_track->format ); - // } - // - // free( name ); - // } - // } + text = aaf_get_indirectValue( aafi->aafd, Indirect, &AAFTypeID_String ); + if ( !text ) { + warning( "Parsing UserComments: Could not retrieve Indirect value for TaggedValue::Value" ); + goto UserCommentError; + } - DUMP_OBJ( aafi, MobSlot, &__td ); + aafiMetaData *Comment = aafi_newMetadata( aafi, metadataList ); + if ( !Comment ) { + warning( "Parsing UserComments: Could not create new UserComment" ); + goto UserCommentError; + } - /* Reset timeline position */ - // aafi->ctx.current_track->current_pos = 0; + Comment->name = name; + Comment->text = text; - aafi_parse_Segment( aafi, Segment, &__td ); - } - else if ( aafUIDCmp( DataDefinition, &AAFDataDef_Timecode ) || - aafUIDCmp( DataDefinition, &AAFDataDef_LegacyTimecode ) ) - { - DUMP_OBJ( aafi, MobSlot, &__td ); - aafi_parse_Segment( aafi, Segment, &__td ); - } - else if ( aafUIDCmp( DataDefinition, &AAFDataDef_Picture ) || - aafUIDCmp( DataDefinition, &AAFDataDef_LegacyPicture ) ) - { + continue; - // debug( "%ls", aaft_ClassIDToText(aafi->aafd, Segment->Class->ID) ); +UserCommentError: + error++; - /* ADP NESTED SCOPE */ + free( name ); + free( text ); + } - // aafObject *NSSegment = NULL; - // aafObject *NSSegments = aaf_get_propertyValue( Segment, PID_NestedScope_Slots ); - // - // aaf_foreach_ObjectInSet( &NSSegment, NSSegments, NULL ) { - // aaf_dump_ObjectProperties( aafi->aafd, NSSegment ); - // } + if ( error ) + return -1; + return 0; +} - if ( aafi->Video->Tracks ) { - DUMP_OBJ_ERROR( aafi, MobSlot, &__td, "Current implementation supports only one video track" ); - return -1; - } +static int retrieve_ControlPoints( AAF_Iface *aafi, aafObject *Points, aafRational_t *times[], aafRational_t *values[] ) +{ + /* + * We do not handle trace here, because there could possibly be hundreds of + * ControlPoints to print, plus retrieve_ControlPoints() is being called before + * VaryingValue Object is logged. + */ - /* - * p.11 : In a CompositionMob or MasterMob, PhysicalTrackNumber is the output channel number that the - * MobSlot should be routed to when played. - */ + *times = calloc( Points->Header->_entryCount, sizeof(aafRational_t) ); + *values = calloc( Points->Header->_entryCount, sizeof(aafRational_t) ); - uint32_t tracknumber = 0; - uint32_t *track_num = aaf_get_propertyValue( MobSlot, PID_MobSlot_PhysicalTrackNumber, &AAFTypeID_UInt32 ); + if ( !*times || !*values ) { + error( "Out of memory" ); + return -1; + } - if ( track_num == NULL ) { /* opt */ - tracknumber = 1; /* Current implementation supports only one video track. */ - } else { - tracknumber = *track_num; - } + aafObject *Point = NULL; + unsigned int i = 0; - aafiVideoTrack *track = aafi_newVideoTrack( aafi ); + AAF_foreach_ObjectInSet( &Point, Points, NULL ) { + if ( !aafUIDCmp( Point->Class->ID, &AAFClassID_ControlPoint ) ) { + error( "Object is not AAFClassID_ControlPoint : %s", aaft_ClassIDToText( aafi->aafd, Point->Class->ID ) ); + continue; + } - track->number = tracknumber; - track->name = aaf_get_propertyValue( MobSlot, PID_MobSlot_SlotName, &AAFTypeID_String ); + aafRational_t *time = aaf_get_propertyValue( Point, PID_ControlPoint_Time, &AAFTypeID_Rational ); - track->edit_rate = edit_rate; + if ( !time ) { + error( "Missing ControlPoint::Time" ); + free( *times ); *times = NULL; + free( *values ); *values = NULL; - DUMP_OBJ( aafi, MobSlot, &__td ); + return -1; + } - aafi_parse_Segment( aafi, Segment, &__td ); + aafIndirect_t *Indirect = aaf_get_propertyValue( Point, PID_ControlPoint_Value, &AAFTypeID_Indirect ); + if ( !Indirect ) { + error( "Missing Indirect ControlPoint::Value" ); - /* update session_end if needed */ - // session_end = ( aafi->ctx.current_track->current_pos > session_end ) ? aafi->ctx.current_track->current_pos : session_end; - } - else { - DUMP_OBJ_NO_SUPPORT( aafi, MobSlot, &__td ); - } + free( *times ); *times = NULL; + free( *values ); *values = NULL; + return -1; } - else if ( aafUIDCmp( MobSlot->Parent->Class->ID, &AAFClassID_MasterMob ) ) { - /* Retrieve Essences */ - - // if ( aafUIDCmp( DataDefinition, &AAFDataDef_Sound ) || - // aafUIDCmp( DataDefinition, &AAFDataDef_LegacySound ) ) - // { - DUMP_OBJ( aafi, MobSlot, &__td ); - aafi_parse_Segment( aafi, Segment, &__td ); - - // } - // else if ( aafUIDCmp( DataDefinition, &AAFDataDef_Picture ) || - // aafUIDCmp( DataDefinition, &AAFDataDef_LegacyPicture ) ) - // { - // aafi_parse_Segment( aafi, Segment ); - // - // retrieve_EssenceData( aafi ); - // } - // else { - // aafi_trace_obj( aafi, MobSlot, ANSI_COLOR_YELLOW ); - // debug( "%ls", aaft_DataDefToText( aafi->aafd, DataDefinition ) ); - // } - } - else if ( aafUIDCmp( MobSlot->Parent->Class->ID, &AAFClassID_SourceMob ) ) { - if ( aafi->ctx.current_essence != NULL ) { - aafiAudioEssence *audioEssence = (aafiAudioEssence*)aafi->ctx.current_essence; - aafPosition_t *Origin = aaf_get_propertyValue( MobSlot, PID_TimelineMobSlot_Origin, &AAFTypeID_PositionType ); + aafRational_t *value = aaf_get_indirectValue( aafi->aafd, Indirect, &AAFTypeID_Rational ); - if ( Origin == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, MobSlot, &__td, "Missing PID_TimelineMobSlot_Origin" ); - return -1; - } + if ( !value ) { + error( "Could not retrieve Indirect value for ControlPoint::Value" ); - audioEssence->timeReference = *Origin; - audioEssence->mobSlotEditRate = edit_rate; + free( *times ); *times = NULL; + free( *values ); *values = NULL; - DUMP_OBJ( aafi, MobSlot, &__td ); - } - else { - DUMP_OBJ_ERROR( aafi, MobSlot, &__td, "aafi->ctx.current_essence no set" ); - } - } - else { - /* Not in CompositionMob, MasterMob, or SourceMob. Can not happen. */ - DUMP_OBJ_NO_SUPPORT( aafi, MobSlot, &__td ); + return -1; } + + memcpy( (*times+i), time, sizeof(aafRational_t) ); + memcpy( (*values+i), value, sizeof(aafRational_t) ); + + i++; } - else if ( aafUIDCmp( MobSlot->Class->ID, &AAFClassID_EventMobSlot ) ) { - aafRational_t *edit_rate = aaf_get_propertyValue( MobSlot, PID_EventMobSlot_EditRate, &AAFTypeID_Rational ); + if ( Points->Header->_entryCount != i ) { + warning( "ControlPoints _entryCount (%i) does not match iteration (%i).", Points->Header->_entryCount, i ); + return (int)i; + } - if ( edit_rate == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, MobSlot, &__td, "Missing PID_EventMobSlot_EditRate" ); - return -1; - } + return (int)Points->Header->_entryCount; +} - aafi->ctx.current_markers_edit_rate = edit_rate; - DUMP_OBJ( aafi, MobSlot, &__td ); - return aafi_parse_Segment( aafi, Segment, &__td ); - } - else { - /* Not AAFClassID_TimelineMobSlot */ - DUMP_OBJ_NO_SUPPORT( aafi, MobSlot, &__td ); - } - return 0; -} @@ -4539,46 +3304,55 @@ int aafi_retrieveData( AAF_Iface *aafi ) __td.pfn = 0; __td.lv = 0; __td.ll = calloc( 1024, sizeof(int) ); + if ( !__td.ll ) { + error( "Out of memory" ); + return -1; + } __td.ll[0] = 0; int compositionMobParsed = 0; aafObject *Mob = NULL; - aaf_foreach_ObjectInSet( &Mob, aafi->aafd->Mobs, NULL ) { + uint32_t i = 0; + AAFI_foreach_ObjectInSet( &Mob, aafi->aafd->Mobs, i, __td ) { if ( aafUIDCmp( Mob->Class->ID, &AAFClassID_MasterMob ) || - aafUIDCmp( Mob->Class->ID, &AAFClassID_SourceMob ) ) { - // DUMP_OBJ_WARNING( aafi, Mob, &__td, "PRINTS FOR DEBUG ONLY: Will be parsed later" ); + aafUIDCmp( Mob->Class->ID, &AAFClassID_SourceMob ) ) + { + // TRACE_OBJ_WARNING( aafi, Mob, &__td, " PRINTS FOR DEBUG ONLY: Will be parsed later" ); continue; } if ( !aafUIDCmp( Mob->Class->ID, &AAFClassID_CompositionMob ) ) { /* there should not be anything other than MasterMob, SourceMob or CompositionMob */ - DUMP_OBJ_NO_SUPPORT( aafi, Mob, &__td ); + TRACE_OBJ_NO_SUPPORT( aafi, Mob, &__td ); continue; } aafUID_t *UsageCode = aaf_get_propertyValue( Mob, PID_Mob_UsageCode, &AAFTypeID_UsageType ); - if ( aafUIDCmp( aafi->aafd->Header.OperationalPattern, &AAFOPDef_EditProtocol ) && - !aafUIDCmp( UsageCode, &AAFUsage_TopLevel ) ) - { + if ( !aafUIDCmp( UsageCode, &AAFUsage_TopLevel ) && (aafUIDCmp( aafi->aafd->Header.OperationalPattern, &AAFOPDef_EditProtocol ) || UsageCode) ) { /* * If we run against AAFOPDef_EditProtocol, we process only TopLevels CompositionMobs. * If there is more than one, we have multiple Compositions in a single AAF. */ + // TRACE_OBJ_WARNING( aafi, Mob, &__td, " PRINTS FOR DEBUG ONLY: Will be parsed later" ); continue; } if ( compositionMobParsed ) { - DUMP_OBJ_ERROR( aafi, Mob, &__td, "Multiple top level CompositionMob not supported yet" ); + TRACE_OBJ_ERROR( aafi, Mob, &__td, "Multiple top level CompositionMob not supported yet" ); continue; } RESET_CONTEXT( aafi->ctx ); - parse_Mob( aafi, Mob ); + __td.fn = __LINE__; + __td.pfn = 0; + __td.lv = 0; + + parse_Mob( aafi, Mob, &__td ); if ( aafUIDCmp( UsageCode, &AAFUsage_TopLevel ) ) { compositionMobParsed = 1; @@ -4589,15 +3363,14 @@ int aafi_retrieveData( AAF_Iface *aafi ) - if ( aafi->Timecode == NULL ) { /* TODO, shouldn't we leave aafi->Timecode as NULL ? */ warning( "No timecode found in file. Setting to 00:00:00:00 @ 25fps" ); - aafiTimecode *tc = calloc( sizeof(aafiTimecode), sizeof(unsigned char) ); + aafiTimecode *tc = calloc( 1, sizeof(aafiTimecode) ); - if ( tc == NULL ) { - error( "calloc() : %s", strerror( errno ) ); + if ( !tc ) { + error( "Out of memory" ); return -1; } @@ -4611,24 +3384,23 @@ int aafi_retrieveData( AAF_Iface *aafi ) - /* Post processing */ - aafiAudioEssence *audioEssence = NULL; + aafiAudioEssenceFile *audioEssenceFile = NULL; - foreachEssence( audioEssence, aafi->Audio->Essences ) { + AAFI_foreachAudioEssenceFile( aafi, audioEssenceFile ) { - if ( !audioEssence->is_embedded ) { + if ( !audioEssenceFile->is_embedded ) { - audioEssence->usable_file_path = aafi_locate_external_essence_file( aafi, audioEssence->original_file_path, aafi->ctx.options.media_location ); + audioEssenceFile->usable_file_path = aafi_locate_external_essence_file( aafi, audioEssenceFile->original_file_path, aafi->ctx.options.media_location ); - if ( audioEssence->usable_file_path == NULL ) { - error( "Could not locate external audio essence file '%ls'", audioEssence->original_file_path ); + if ( audioEssenceFile->usable_file_path == NULL ) { + warning( "Could not locate external audio essence file '%s'", audioEssenceFile->original_file_path ); } } - if ( audioEssence->summary || audioEssence->usable_file_path ) { - aafi_parse_audio_essence( aafi, audioEssence ); + if ( audioEssenceFile->summary || audioEssenceFile->usable_file_path ) { + aafi_parse_audio_essence( aafi, audioEssenceFile ); } } @@ -4640,47 +3412,47 @@ int aafi_retrieveData( AAF_Iface *aafi ) uint32_t maxOccurence = 0; - foreachEssence( audioEssence, aafi->Audio->Essences ) { + AAFI_foreachAudioEssenceFile( aafi, audioEssenceFile ) { uint32_t count = 1; - aafiAudioEssence *ae = NULL; + aafiAudioEssenceFile *ae = NULL; - if ( audioEssence->samplerate == aafi->Audio->samplerate && - audioEssence->samplesize == aafi->Audio->samplesize ) + if ( audioEssenceFile->samplerate == aafi->Audio->samplerate && + audioEssenceFile->samplesize == aafi->Audio->samplesize ) { continue; } - foreachEssence( ae, audioEssence->next ) { - if ( audioEssence->samplerate == ae->samplerate && audioEssence->samplesize == ae->samplesize ) { + AAFI_foreachEssence( audioEssenceFile->next, ae ) { + if ( audioEssenceFile->samplerate == ae->samplerate && audioEssenceFile->samplesize == ae->samplesize ) { count++; } } - debug( "Essence count @ %u Hz / %u bits : %i", audioEssence->samplerate, audioEssence->samplesize, count ); + debug( "Essence count @ %u Hz / %u bits : %i", audioEssenceFile->samplerate, audioEssenceFile->samplesize, count ); if ( count > maxOccurence ) { maxOccurence = count; - aafi->Audio->samplesize = audioEssence->samplesize; - aafi->Audio->samplerate = audioEssence->samplerate; - aafi->Audio->samplerateRational = audioEssence->samplerateRational; + aafi->Audio->samplesize = audioEssenceFile->samplesize; + aafi->Audio->samplerate = audioEssenceFile->samplerate; + aafi->Audio->samplerateRational = audioEssenceFile->samplerateRational; } } - aafiVideoEssence *videoEssence = NULL; + aafiVideoEssence *videoEssenceFile = NULL; - foreachEssence( videoEssence, aafi->Video->Essences ) { + AAFI_foreachVideoEssence( aafi, videoEssenceFile ) { - if ( videoEssence->original_file_path == NULL ) { + if ( videoEssenceFile->original_file_path == NULL ) { continue; } - videoEssence->usable_file_path = aafi_locate_external_essence_file( aafi, videoEssence->original_file_path, aafi->ctx.options.media_location ); + videoEssenceFile->usable_file_path = aafi_locate_external_essence_file( aafi, videoEssenceFile->original_file_path, aafi->ctx.options.media_location ); - if ( videoEssence->usable_file_path == NULL ) { - error( "Could not locate external video essence file '%ls'", videoEssence->original_file_path ); + if ( videoEssenceFile->usable_file_path == NULL ) { + error( "Could not locate external video essence file '%s'", videoEssenceFile->original_file_path ); continue; } } @@ -4689,16 +3461,16 @@ int aafi_retrieveData( AAF_Iface *aafi ) aafPosition_t trackEnd = 0; aafiAudioTrack *audioTrack = NULL; - foreach_audioTrack( audioTrack, aafi ) { + AAFI_foreachAudioTrack( aafi, audioTrack ) { if ( aafi->compositionLength_editRate ) { - trackEnd = laaf_util_converUnit( audioTrack->current_pos, audioTrack->edit_rate, aafi->compositionLength_editRate ); + trackEnd = aafi_convertUnit( audioTrack->current_pos, audioTrack->edit_rate, aafi->compositionLength_editRate ); } else { trackEnd = audioTrack->current_pos; } if ( trackEnd > aafi->compositionLength ) { - debug( "Setting compositionLength with audio track \"%ls\" (%u) : %"PRIi64, audioTrack->name, audioTrack->number, audioTrack->current_pos ); + debug( "Setting compositionLength with audio track \"%s\" (%u) : %"PRIi64, audioTrack->name, audioTrack->number, audioTrack->current_pos ); aafi->compositionLength = audioTrack->current_pos; aafi->compositionLength_editRate = audioTrack->edit_rate; } @@ -4706,7 +3478,7 @@ int aafi_retrieveData( AAF_Iface *aafi ) aafiTimelineItem *audioItem = NULL; aafiAudioClip *audioClip = NULL; - foreach_Item( audioItem, audioTrack ) { + AAFI_foreachTrackItem( audioTrack, audioItem ) { if ( audioItem->type == AAFI_TRANS ) { continue; @@ -4720,16 +3492,16 @@ int aafi_retrieveData( AAF_Iface *aafi ) aafiVideoTrack *videoTrack = NULL; - foreach_videoTrack( videoTrack, aafi ) { + AAFI_foreachVideoTrack( aafi, videoTrack ) { if ( aafi->compositionLength_editRate ) { - trackEnd = laaf_util_converUnit( videoTrack->current_pos, videoTrack->edit_rate, aafi->compositionLength_editRate ); + trackEnd = aafi_convertUnit( videoTrack->current_pos, videoTrack->edit_rate, aafi->compositionLength_editRate ); } else { trackEnd = videoTrack->current_pos; } if ( trackEnd > aafi->compositionLength ) { - debug( "Setting compositionLength with video track \"%ls\" (%u) : %"PRIi64, videoTrack->name, videoTrack->number, videoTrack->current_pos ); + debug( "Setting compositionLength with video track \"%s\" (%u) : %"PRIi64, videoTrack->name, videoTrack->number, videoTrack->current_pos ); aafi->compositionLength = videoTrack->current_pos; aafi->compositionLength_editRate = videoTrack->edit_rate; } @@ -4746,6 +3518,476 @@ int aafi_retrieveData( AAF_Iface *aafi ) return 0; } + + +void aafi_dump_obj( AAF_Iface *aafi, aafObject *Obj, struct trace_dump *__td, int state, const char *func, int line, const char *fmt, ... ) +{ + va_list args; + struct aafLog *log = aafi->log; + + + if ( aafi->ctx.options.trace == 0 ) { + + enum verbosityLevel_e verbtype = VERB_QUIET; + + switch ( state ) { + case TD_ERROR: verbtype = VERB_ERROR; break; + case TD_WARNING: + case TD_NOT_SUPPORTED: verbtype = VERB_WARNING; break; + // case TD_INFO: + // case TD_OK: verbtype = VERB_DEBUG; break; + default: + return; + } + + if ( aafi->log->verb < verbtype ) { + return; + } + + + char *buf = NULL; + + va_start( args, fmt ); + + int rc = laaf_util_vsnprintf_realloc( &buf, NULL, 0, fmt, args ); + + va_end( args ); + + if ( rc < 0 ) { + LOG_BUFFER_WRITE( log, "laaf_util_vsnprintf_realloc() error" ); + return; + } + + laaf_write_log( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __FILENAME__, func, line, buf ); + + free( buf ); + + return; + } + + + if ( Obj ) { + + switch ( state ) { + case TD_ERROR: LOG_BUFFER_WRITE( log, "%serr %s%s %s", ANSI_COLOR_RED(log), ANSI_COLOR_DARKGREY(log), TREE_LINE, ANSI_COLOR_RED(log) ); break; + case TD_WARNING: LOG_BUFFER_WRITE( log, "%swrn %s%s %s", ANSI_COLOR_YELLOW(log), ANSI_COLOR_DARKGREY(log), TREE_LINE, ANSI_COLOR_YELLOW(log) ); break; + case TD_NOT_SUPPORTED: LOG_BUFFER_WRITE( log, "%suns %s%s %s", ANSI_COLOR_ORANGE(log), ANSI_COLOR_DARKGREY(log), TREE_LINE, ANSI_COLOR_ORANGE(log) ); break; + default: LOG_BUFFER_WRITE( log, " %s%s ", ANSI_COLOR_DARKGREY(log), TREE_LINE ); break; + } + LOG_BUFFER_WRITE( log, "%05i", line ); + } + else { + LOG_BUFFER_WRITE( log, " %s%s%s ", ANSI_COLOR_DARKGREY(log), TREE_LINE, ANSI_COLOR_RESET(log) ); + } + + LOG_BUFFER_WRITE( log, "%s%s%s", ANSI_COLOR_DARKGREY(log), TREE_LINE, ANSI_COLOR_RESET(log) ); /* │ */ + + /* Print left padding and vertical lines */ + + if ( __td->lv > 0 ) { + + for ( int i = 0; i < __td->lv; i++ ) { + + /* current level iteration has more than one entry remaining in loop */ + + if ( __td->ll[i] > 1 ) { + + /* next level iteration is current trace */ + + if ( i+1 == __td->lv ) { + if ( Obj ) { + LOG_BUFFER_WRITE( log, "%s ", TREE_ENTRY ); /* ├── */ + } + else { + LOG_BUFFER_WRITE( log, "%s ", TREE_PADDED_LINE ); /* │ */ + } + } + else { + LOG_BUFFER_WRITE( log, "%s ", TREE_PADDED_LINE ); /* │ */ + } + } + else if ( i+1 == __td->lv && Obj ) { + LOG_BUFFER_WRITE( log, "%s ", TREE_LAST_ENTRY ); /* └── */ + } + else { + LOG_BUFFER_WRITE( log, " " ); + } + } + } + + + if ( Obj ) { + + switch ( state ) { + case TD_ERROR: LOG_BUFFER_WRITE( log, "%s", ANSI_COLOR_RED(log) ); break; + case TD_WARNING: LOG_BUFFER_WRITE( log, "%s", ANSI_COLOR_YELLOW(log) ); break; + case TD_NOT_SUPPORTED: LOG_BUFFER_WRITE( log, "%s", ANSI_COLOR_ORANGE(log) ); break; + case TD_INFO: + case TD_OK: LOG_BUFFER_WRITE( log, "%s", ANSI_COLOR_CYAN(log) ); break; + } + + + LOG_BUFFER_WRITE( log, "%s ", aaft_ClassIDToText(aafi->aafd, Obj->Class->ID) ); + + LOG_BUFFER_WRITE( log, "%s", ANSI_COLOR_RESET(log) ); + + + if ( aaf_ObjectInheritsClass( Obj, &AAFClassID_Mob ) ) { + + aafMobID_t *mobID = aaf_get_propertyValue( Obj, PID_Mob_MobID, &AAFTypeID_MobIDType ); + char *name = aaf_get_propertyValue( Obj, PID_Mob_Name, &AAFTypeID_String ); + aafUID_t *usageCode = aaf_get_propertyValue( Obj, PID_Mob_UsageCode, &AAFTypeID_UsageType ); + + LOG_BUFFER_WRITE( log, "(UsageCode: %s%s%s) %s%s", + ANSI_COLOR_DARKGREY(log), + aaft_UsageCodeToText( usageCode ), + ANSI_COLOR_RESET(log), + (name && name[0] != 0x00) ? ": " : "", + (name) ? name : "" + ); + + free( name ); + + LOG_BUFFER_WRITE( log, " MobID: %s%s%s", + ANSI_COLOR_DARKGREY(log), + (mobID) ? aaft_MobIDToText( mobID ) : "none", + ANSI_COLOR_RESET(log) ); + } + else if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_TimelineMobSlot ) ) + { + aafObject *Segment = aaf_get_propertyValue( Obj, PID_MobSlot_Segment, &AAFTypeID_SegmentStrongReference ); + char *name = aaf_get_propertyValue( Obj, PID_MobSlot_SlotName, &AAFTypeID_String ); + uint32_t *slotID = aaf_get_propertyValue( Obj, PID_MobSlot_SlotID, &AAFTypeID_UInt32 ); + uint32_t *trackNo = aaf_get_propertyValue( Obj, PID_MobSlot_PhysicalTrackNumber, &AAFTypeID_UInt32 ); + aafUID_t *DataDefinition = NULL; + + aafWeakRef_t *dataDefWeakRef = aaf_get_propertyValue( Segment, PID_Component_DataDefinition, &AAFTypeID_DataDefinitionWeakReference ); + + if ( dataDefWeakRef ) { + DataDefinition = aaf_get_DataIdentificationByWeakRef( aafi->aafd, dataDefWeakRef ); + } + + LOG_BUFFER_WRITE( log, "[slot:%s%i%s track:%s%i%s] (DataDef: %s%s%s) %s%s ", + ANSI_COLOR_BOLD(log), + (slotID) ? (int)(*slotID) : -1, + ANSI_COLOR_RESET(log), + ANSI_COLOR_BOLD(log), + (trackNo) ? (int)(*trackNo) : -1, + ANSI_COLOR_RESET(log), + (state == TD_NOT_SUPPORTED) ? ANSI_COLOR_ORANGE(log) : ANSI_COLOR_DARKGREY(log), + aaft_DataDefToText( aafi->aafd, DataDefinition ), + ANSI_COLOR_RESET(log), + (name && name[0] != 0x00) ? ": " : "", + (name) ? name : "" + ); + + free( name ); + } + else if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_OperationGroup ) ) { + + aafUID_t *OperationIdentification = NULL; + + aafWeakRef_t *OperationDefWeakRef = aaf_get_propertyValue( Obj, PID_OperationGroup_Operation, &AAFTypeID_OperationDefinitionWeakReference ); + + if ( OperationDefWeakRef ) { + OperationIdentification = aaf_get_OperationIdentificationByWeakRef( aafi->aafd, OperationDefWeakRef ); + } + + int64_t *length = aaf_get_propertyValue( Obj, PID_Component_Length, &AAFTypeID_LengthType ); + + LOG_BUFFER_WRITE( log, "(OpIdent: %s%s%s; Length: %s%li%s) ", + (state == TD_NOT_SUPPORTED) ? ANSI_COLOR_ORANGE(log) : ANSI_COLOR_DARKGREY(log), + aaft_OperationDefToText( aafi->aafd, OperationIdentification ), + ANSI_COLOR_RESET(log), + ANSI_COLOR_DARKGREY(log), + (length) ? *length : -1, + ANSI_COLOR_RESET(log) + ); + } + else if ( aaf_ObjectInheritsClass( Obj, &AAFClassID_Component ) ) + { + int64_t *length = aaf_get_propertyValue( Obj, PID_Component_Length, &AAFTypeID_LengthType ); + + LOG_BUFFER_WRITE( log, "(Length: %s%li%s", + ANSI_COLOR_DARKGREY(log), + (length) ? *length : -1, + ANSI_COLOR_RESET(log) + ); + + if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_Transition ) ) { + aafPosition_t *cutPoint = aaf_get_propertyValue( Obj, PID_Transition_CutPoint, &AAFTypeID_PositionType ); + + if ( cutPoint ) { + LOG_BUFFER_WRITE( log, "; CutPoint: %s%li%s", + ANSI_COLOR_DARKGREY(log), + *cutPoint, + ANSI_COLOR_RESET(log) + ); + } + } + + LOG_BUFFER_WRITE( log, ")" ); + } + else if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_ConstantValue ) ) { + + aafIndirect_t *Indirect = aaf_get_propertyValue( Obj, PID_ConstantValue_Value, &AAFTypeID_Indirect ); + + if ( Indirect ) { + + aafUID_t *ParamDef = aaf_get_propertyValue( Obj, PID_Parameter_Definition, &AAFTypeID_AUID ); + + LOG_BUFFER_WRITE( log, "(ParamDef: %s%s%s; Type: %s%s%s) ", + (state == TD_NOT_SUPPORTED) ? ANSI_COLOR_ORANGE(log) : ANSI_COLOR_DARKGREY(log), + aaft_ParameterToText( aafi->aafd, ParamDef ), + ANSI_COLOR_RESET(log), + ANSI_COLOR_DARKGREY(log), + aaft_TypeIDToText( &Indirect->TypeDef ), + ANSI_COLOR_RESET(log) + ); + + LOG_BUFFER_WRITE( log, ": %s%s%s", + ANSI_COLOR_DARKGREY(log), + aaft_IndirectValueToText( aafi->aafd, Indirect ), + ANSI_COLOR_RESET(log) ); + + if ( aafUIDCmp( ParamDef, &AAFParameterDef_Amplitude ) && + aafUIDCmp( &Indirect->TypeDef, &AAFTypeID_Rational ) ) + { + aafRational_t *value = aaf_get_indirectValue( aafi->aafd, Indirect, NULL ); + + LOG_BUFFER_WRITE( log, " %s(%+05.1lf dB)%s", + ANSI_COLOR_DARKGREY(log), + 20 * log10( aafRationalToDouble( *value ) ), + ANSI_COLOR_RESET(log) ); + } + + __td->eob = 0; + } + } + else if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_VaryingValue ) ) { + + aafUID_t *ParamDef = aaf_get_propertyValue( Obj, PID_Parameter_Definition, &AAFTypeID_AUID ); + aafUID_t *InterpolationIdentification = NULL; + + aafWeakRef_t *InterpolationDefWeakRef = aaf_get_propertyValue( Obj, PID_VaryingValue_Interpolation, &AAFTypeID_InterpolationDefinitionWeakReference ); + + if ( InterpolationDefWeakRef ) { + InterpolationIdentification = aaf_get_InterpolationIdentificationByWeakRef( aafi->aafd, InterpolationDefWeakRef ); + } + + LOG_BUFFER_WRITE( log, " (ParamDef: %s%s%s; Interpol: %s%s%s) ", + (state == TD_NOT_SUPPORTED) ? ANSI_COLOR_ORANGE(log) : ANSI_COLOR_DARKGREY(log), + aaft_ParameterToText( aafi->aafd, ParamDef ), + ANSI_COLOR_RESET(log), + ANSI_COLOR_DARKGREY(log), + aaft_InterpolationToText( InterpolationIdentification ), + ANSI_COLOR_RESET(log) + ); + + __td->eob = 0; + } + else if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_NetworkLocator ) ) { + + char *url = aaf_get_propertyValue( Obj, PID_NetworkLocator_URLString, &AAFTypeID_String ); + + if ( url ) { + LOG_BUFFER_WRITE( log, "(URLString: %s%s%s)", + ANSI_COLOR_DARKGREY(log), + url, + ANSI_COLOR_RESET(log) ); + + free( url ); + } + } + else if ( aafUIDCmp( Obj->Class->ID, &AAFClassID_EssenceData ) ) { + + char *streamName = aaf_get_propertyValue( Obj, PID_EssenceData_Data, &AAFTypeID_String ); + + if ( streamName ) { + LOG_BUFFER_WRITE( log, "(Data: %s%s%s)", + ANSI_COLOR_DARKGREY(log), + streamName, + ANSI_COLOR_RESET(log) ); + + free( streamName ); + } + } + else if ( aaf_ObjectInheritsClass( Obj, &AAFClassID_FileDescriptor ) ) { + + aafUID_t *ContainerFormat = NULL; + + aafWeakRef_t *ContainerDefWeakRef = aaf_get_propertyValue( Obj, PID_FileDescriptor_ContainerFormat, &AAFTypeID_ClassDefinitionWeakReference ); + + if ( ContainerDefWeakRef ) { + ContainerFormat = aaf_get_ContainerIdentificationByWeakRef( aafi->aafd, ContainerDefWeakRef ); + } + + LOG_BUFFER_WRITE( log, "(ContainerIdent : %s%s%s)", + ANSI_COLOR_DARKGREY(log), + aaft_ContainerToText(ContainerFormat), + ANSI_COLOR_RESET(log) ); + } + + + if ( state == TD_INFO ) { + LOG_BUFFER_WRITE( log, ": %s", ANSI_COLOR_CYAN(log) ); + } + else if ( state == TD_WARNING ) { + LOG_BUFFER_WRITE( log, ": %s", ANSI_COLOR_YELLOW(log) ); + } + else if ( state == TD_ERROR ) { + LOG_BUFFER_WRITE( log, ": %s", ANSI_COLOR_RED(log) ); + } + + va_start( args, fmt ); + + int rc = laaf_util_vsnprintf_realloc( &log->_msg, &log->_msg_size, log->_msg_pos, fmt, args ); + + if ( rc < 0 ) { + LOG_BUFFER_WRITE( log, "laaf_util_vsnprintf_realloc() error" ); + } else { + log->_msg_pos += (size_t)rc; + } + + va_end( args ); + + + if ( state == TD_ERROR || state == TD_INFO ) { + LOG_BUFFER_WRITE( log, "." ); + } + + + int hasUnknownProps = 0; + + if ( !aafi->ctx.options.dump_class_aaf_properties ) { + + aafProperty * Prop = NULL; + + for ( Prop = Obj->Properties; Prop != NULL; Prop = Prop->next ) { + if ( Prop->def->meta ) { + LOG_BUFFER_WRITE( log, "%s%s %s[0x%04x]", ANSI_COLOR_RESET(log), (!hasUnknownProps) ? " (MetaProps:" : "", aaft_PIDToText( aafi->aafd, Prop->pid ), Prop->pid ); + hasUnknownProps++; + } + } + + if ( hasUnknownProps ) { + LOG_BUFFER_WRITE( log, ")" ); + } + } + + if ( aafi->ctx.options.dump_tagged_value ) { + if ( aaf_ObjectInheritsClass( Obj, &AAFClassID_Mob ) ) { + + aafObject *UserComments = aaf_get_propertyValue( Obj, PID_Mob_UserComments, &AAFTypeID_TaggedValueStrongReferenceVector ); + aafObject *Attributes = aaf_get_propertyValue( Obj, PID_Mob_Attributes, &AAFTypeID_TaggedValueStrongReferenceVector ); + + if ( UserComments ) { + LOG_BUFFER_WRITE( log, "\n Mob::UserComments:\n" ); + aaf_dump_TaggedValueSet( aafi->aafd, UserComments, " " ); + } + if ( Attributes ) { + LOG_BUFFER_WRITE( log, "\n Mob::Attributes:\n" ); + aaf_dump_TaggedValueSet( aafi->aafd, Attributes, " " ); + } + } + else if ( aaf_ObjectInheritsClass( Obj, &AAFClassID_Component ) ) { + + aafObject *UserComments = aaf_get_propertyValue( Obj, PID_Component_UserComments, &AAFTypeID_TaggedValueStrongReferenceVector ); + aafObject *Attributes = aaf_get_propertyValue( Obj, PID_Component_Attributes, &AAFTypeID_TaggedValueStrongReferenceVector ); + + if ( UserComments ) { + LOG_BUFFER_WRITE( log, "\n Component::UserComments:\n" ); + aaf_dump_TaggedValueSet( aafi->aafd, UserComments, " " ); + } + if ( Attributes ) { + LOG_BUFFER_WRITE( log, "\n Component::Attributes:\n" ); + aaf_dump_TaggedValueSet( aafi->aafd, Attributes, " " ); + } + } + } + + if ( aafi->ctx.options.dump_meta && hasUnknownProps ) { + + LOG_BUFFER_WRITE( log, "\n\n%s", ANSI_COLOR_MAGENTA(log) ); + LOG_BUFFER_WRITE( log, " ======================================================================\n" ); + LOG_BUFFER_WRITE( log, " AAF Meta Properties Dump\n" ); + LOG_BUFFER_WRITE( log, " ======================================================================\n" ); + LOG_BUFFER_WRITE( log, "%s", ANSI_COLOR_RESET(log) ); + + aafProperty * Prop = NULL; + + for ( Prop = Obj->Properties; Prop != NULL; Prop = Prop->next ) { + + if ( Prop->def->meta ) { + if ( aafi->ctx.options.dump_meta ) { + + if ( Prop->sf == SF_STRONG_OBJECT_REFERENCE_VECTOR ) { + + LOG_BUFFER_WRITE( log, "\n" ); + LOG_BUFFER_WRITE( log, " [%s0x%04x%s] %s (%s)\n", + ANSI_COLOR_MAGENTA(log), + Prop->pid, + ANSI_COLOR_RESET(log), + aaft_PIDToText( aafi->aafd, Prop->pid ), + aaft_StoredFormToText( Prop->sf ) ); + + void *propValue = aaf_get_propertyValue( Obj, Prop->pid, &AAFTypeID_TaggedValueStrongReferenceVector ); + + log->color_reset = ANSI_COLOR_MAGENTA(log); + aaf_dump_TaggedValueSet( aafi->aafd, propValue, " " ); + log->color_reset = NULL; + } + else { + LOG_BUFFER_WRITE( log, "\n" ); + aaf_dump_ObjectProperty( aafi->aafd, Prop, " " ); + } + } + } + } + } + + if ( aafi->ctx.options.dump_class_raw_properties && strcmp( aaft_ClassIDToText(aafi->aafd, Obj->Class->ID), aafi->ctx.options.dump_class_raw_properties ) == 0 ) { + LOG_BUFFER_WRITE( log, "\n\n" ); + LOG_BUFFER_WRITE( log, " ======================================================================\n" ); + LOG_BUFFER_WRITE( log, " CFB Object Properties Dump\n" ); + LOG_BUFFER_WRITE( log, " ======================================================================\n" ); + LOG_BUFFER_WRITE( log, "%s", ANSI_COLOR_DARKGREY(log) ); + LOG_BUFFER_WRITE( log, " %s\n", aaft_ClassIDToText(aafi->aafd, Obj->Class->ID) ); + LOG_BUFFER_WRITE( log, " %s/properties\n", aaf_get_ObjectPath( Obj ) ); + LOG_BUFFER_WRITE( log, "%s\n\n", ANSI_COLOR_RESET(log) ); + + aaf_dump_nodeStreamProperties( aafi->aafd, cfb_getChildNode( aafi->aafd->cfbd, "properties", Obj->Node ), " " ); + + LOG_BUFFER_WRITE( log, "\n" ); + } + + if ( aafi->ctx.options.dump_class_aaf_properties && strcmp( aaft_ClassIDToText(aafi->aafd, Obj->Class->ID), aafi->ctx.options.dump_class_aaf_properties ) == 0 ) { + LOG_BUFFER_WRITE( log, "\n\n" ); + LOG_BUFFER_WRITE( log, " ======================================================================\n" ); + LOG_BUFFER_WRITE( log, " AAF Properties Dump\n" ); + LOG_BUFFER_WRITE( log, " ======================================================================\n" ); + LOG_BUFFER_WRITE( log, "%s", ANSI_COLOR_DARKGREY(log) ); + LOG_BUFFER_WRITE( log, " %s\n", aaft_ClassIDToText(aafi->aafd, Obj->Class->ID) ); + LOG_BUFFER_WRITE( log, " %s/properties\n", aaf_get_ObjectPath( Obj ) ); + LOG_BUFFER_WRITE( log, "%s\n\n", ANSI_COLOR_RESET(log) ); + + aaf_dump_ObjectProperties( aafi->aafd, Obj, " " ); + + LOG_BUFFER_WRITE( log, "\n" ); + } + + LOG_BUFFER_WRITE( log, "%s", ANSI_COLOR_RESET(log) ); + } + + + log->debug_callback( log, (void*)aafi, DEBUG_SRC_ID_TRACE, 0, "", "", 0, log->_msg, log->user ); + + + /* if end of branch, print one line padding */ + if ( Obj && ( __td->eob || state == TD_ERROR ) ) + aafi_dump_obj( aafi, NULL, __td, 0, NULL, -1, "" ); +} + /** * @} */ diff --git a/src/AAFIface/AAFIface.c b/src/AAFIface/AAFIface.c index f3d7f58..5dd736c 100644 --- a/src/AAFIface/AAFIface.c +++ b/src/AAFIface/AAFIface.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -43,9 +43,10 @@ #include #include #include +#include #include -#include +#include #include #include @@ -57,54 +58,53 @@ #define debug( ... ) \ - _dbg( aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) #define warning( ... ) \ - _dbg( aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) #define error( ... ) \ - _dbg( aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) - + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) AAF_Iface * aafi_alloc( AAF_Data *aafd ) { - AAF_Iface *aafi = calloc( sizeof(AAF_Iface), sizeof(unsigned char) ); + AAF_Iface *aafi = calloc( 1, sizeof(AAF_Iface) ); - if ( aafi == NULL ) { + if ( !aafi ) { return NULL; } - aafi->dbg = laaf_new_debug(); + aafi->log = laaf_new_log(); - if ( aafi->dbg == NULL ) { + if ( !aafi->log ) { goto err; } - aafi->Audio = calloc( sizeof(aafiAudio), sizeof(unsigned char) ); + aafi->Audio = calloc( 1, sizeof(aafiAudio) ); - if ( aafi->Audio == NULL ) { + if ( !aafi->Audio ) { goto err; } - aafi->Video = calloc( sizeof(aafiVideo), sizeof(unsigned char) ); + aafi->Video = calloc( 1, sizeof(aafiVideo) ); - if ( aafi->Video == NULL ) { + if ( !aafi->Video ) { goto err; } - if ( aafd != NULL ) { + if ( aafd ) { aafi->aafd = aafd; } else { - aafi->aafd = aaf_alloc( aafi->dbg ); + aafi->aafd = aaf_alloc( aafi->log ); - if ( aafi->aafd == NULL ) { + if ( !aafi->aafd ) { goto err; } } @@ -119,19 +119,30 @@ AAF_Iface * aafi_alloc( AAF_Data *aafd ) -void aafi_set_debug( AAF_Iface *aafi, verbosityLevel_e v, int ansicolor, FILE *fp, void (*callback)(struct dbg *dbg, void *ctxdata, int lib, int type, const char *srcfile, const char *srcfunc, int lineno, const char *msg, void *user), void *user ) +void aafi_set_debug( AAF_Iface *aafi, verbosityLevel_e v, int ansicolor, FILE *fp, void (*callback)(struct aafLog *log, void *ctxdata, int lib, int type, const char *srcfile, const char *srcfunc, int lineno, const char *msg, void *user), void *user ) { - aafi->dbg->verb = v; - aafi->dbg->ansicolor = ansicolor; - aafi->dbg->fp = fp; + if ( !aafi ) { + return; + } + + aafi->log->verb = v; + aafi->log->ansicolor = ansicolor; + aafi->log->fp = fp; if ( callback ) { - aafi->dbg->debug_callback = callback; + aafi->log->debug_callback = callback; } if ( user ) { - aafi->dbg->user = user; + aafi->log->user = user; } + +#ifdef _WIN32 + /* we dont want junk bytes to be printed to a windows file */ + if ( fp != stdout && fp != stderr ) { + aafi->log->ansicolor = 0; + } +#endif } @@ -142,20 +153,20 @@ int aafi_set_option_int( AAF_Iface *aafi, const char *optname, int val ) { aafi->ctx.options.trace = val; return 0; } - else if ( strcmp( optname, "trace_meta" ) == 0 ) { - aafi->ctx.options.trace_meta = val; + else if ( strcmp( optname, "dump_meta" ) == 0 ) { + aafi->ctx.options.dump_meta = val; return 0; } - else if ( strcmp( optname, "forbid_nonlatin_filenames" ) == 0 ) { - aafi->ctx.options.forbid_nonlatin_filenames = val; + else if ( strcmp( optname, "dump_tagged_value" ) == 0 ) { + aafi->ctx.options.dump_tagged_value = val; return 0; } else if ( strcmp( optname, "protools" ) == 0 ) { aafi->ctx.options.protools = val; return 0; } - else if ( strcmp( optname, "resolve" ) == 0 ) { - aafi->ctx.options.resolve = val; + else if ( strcmp( optname, "mobid_essence_filename" ) == 0 ) { + aafi->ctx.options.mobid_essence_filename = val; return 0; } @@ -167,29 +178,21 @@ int aafi_set_option_int( AAF_Iface *aafi, const char *optname, int val ) { int aafi_set_option_str( AAF_Iface *aafi, const char *optname, const char *val ) { if ( strcmp( optname, "media_location" ) == 0 ) { + free( aafi->ctx.options.media_location ); + aafi->ctx.options.media_location = laaf_util_c99strdup( val ); - if ( aafi->ctx.options.media_location ) { - free( aafi->ctx.options.media_location ); + if ( val && !aafi->ctx.options.media_location ) { + return -1; } - aafi->ctx.options.media_location = (val) ? laaf_util_c99strdup( val ) : NULL; - return 0; } else if ( strcmp( optname, "dump_class_aaf_properties" ) == 0 ) { - if ( aafi->ctx.options.dump_class_aaf_properties ) { - free( aafi->ctx.options.dump_class_aaf_properties ); - aafi->ctx.options.dump_class_aaf_properties = NULL; - } - - if ( val == NULL ) { - return 0; - } - - aafi->ctx.options.dump_class_aaf_properties = laaf_util_str2wstr( val ); + free( aafi->ctx.options.dump_class_aaf_properties ); + aafi->ctx.options.dump_class_aaf_properties = laaf_util_c99strdup( val ); - if ( aafi->ctx.options.dump_class_aaf_properties == NULL ) { + if ( val && !aafi->ctx.options.dump_class_aaf_properties ) { return -1; } @@ -197,18 +200,10 @@ int aafi_set_option_str( AAF_Iface *aafi, const char *optname, const char *val ) } else if ( strcmp( optname, "dump_class_raw_properties" ) == 0 ) { - if ( aafi->ctx.options.dump_class_raw_properties ) { - free( aafi->ctx.options.dump_class_raw_properties ); - aafi->ctx.options.dump_class_raw_properties = NULL; - } - - if ( val == NULL ) { - return 0; - } - - aafi->ctx.options.dump_class_raw_properties = laaf_util_str2wstr( val ); + free( aafi->ctx.options.dump_class_raw_properties ); + aafi->ctx.options.dump_class_raw_properties = laaf_util_c99strdup( val ); - if ( aafi->ctx.options.dump_class_raw_properties == NULL ) { + if ( val && !aafi->ctx.options.dump_class_raw_properties ) { return -1; } @@ -220,101 +215,101 @@ int aafi_set_option_str( AAF_Iface *aafi, const char *optname, const char *val ) -void aafi_release( AAF_Iface **aafi ) +int aafi_load_file( AAF_Iface *aafi, const char *file ) { - if ( *aafi == NULL ) { - return; + if ( !aafi || !file || aaf_load_file( aafi->aafd, file ) ) { + return 1; } - aaf_release( &(*aafi)->aafd ); + aafi_retrieveData( aafi ); + return 0; +} - if ( (*aafi)->compositionName != NULL ) { - free( (*aafi)->compositionName ); - } - if ( (*aafi)->Comments ) { - aafi_freeUserComments( &((*aafi)->Comments) ); +void aafi_release( AAF_Iface **aafi ) +{ + if ( !aafi || !(*aafi) ) { + return; } + aaf_release( &(*aafi)->aafd ); if ( (*aafi)->Audio != NULL ) { - if ( (*aafi)->Audio->Tracks != NULL ) { - aafi_freeAudioTracks( &(*aafi)->Audio->Tracks ); - } - - if ( (*aafi)->Audio->Essences != NULL ) { - aafi_freeAudioEssences( &(*aafi)->Audio->Essences ); - } + aafi_freeAudioTracks( &(*aafi)->Audio->Tracks ); + aafi_freeAudioEssences( &(*aafi)->Audio->essenceFiles ); free( (*aafi)->Audio ); } - if ( (*aafi)->Video != NULL ) { - if ( (*aafi)->Video->Tracks != NULL ) { - aafi_freeVideoTracks( &(*aafi)->Video->Tracks ); - } - - if ( (*aafi)->Video->Essences != NULL ) { - aafi_freeVideoEssences( &(*aafi)->Video->Essences ); - } + aafi_freeVideoTracks( &(*aafi)->Video->Tracks ); + aafi_freeVideoEssences( &(*aafi)->Video->essenceFiles ); free( (*aafi)->Video ); } - if ( (*aafi)->Markers ) { - aafi_freeMarkers( &(*aafi)->Markers ); - } + aafi_freeMarkers( &(*aafi)->Markers ); + aafi_freeMetadata( &((*aafi)->metadata) ); - if ( (*aafi)->ctx.options.dump_class_aaf_properties ) { - free( (*aafi)->ctx.options.dump_class_aaf_properties ); - } + free( (*aafi)->compositionName ); - if ( (*aafi)->ctx.options.dump_class_raw_properties ) { - free( (*aafi)->ctx.options.dump_class_raw_properties ); - } + free( (*aafi)->ctx.options.dump_class_aaf_properties ); + free( (*aafi)->ctx.options.dump_class_raw_properties ); + free( (*aafi)->ctx.options.media_location ); + free( (*aafi)->Timecode ); - if ( (*aafi)->ctx.options.media_location ) { - free( (*aafi)->ctx.options.media_location ); - } + laaf_free_log( (*aafi)->log ); + free( *aafi ); - if ( (*aafi)->Timecode != NULL ) { - free( (*aafi)->Timecode ); - } + *aafi = NULL; +} - if ( (*aafi)->dbg ) { - laaf_free_debug( (*aafi)->dbg ); - } - free( *aafi ); - *aafi = NULL; +aafiAudioClip * aafi_timelineItemToAudioClip( aafiTimelineItem *audioItem ) +{ + if ( !audioItem || audioItem->type != AAFI_AUDIO_CLIP ) { + return NULL; + } + + return audioItem->data; } -int aafi_load_file( AAF_Iface *aafi, const char * file ) +aafiTransition * aafi_timelineItemToCrossFade( aafiTimelineItem *audioItem ) { - if ( aaf_load_file( aafi->aafd, file ) ) { - error( "Could not load file : %s\n", file ); - return 1; + if ( !audioItem || audioItem->type != AAFI_TRANS ) { + return NULL; } - aafi_retrieveData( aafi ); + aafiTransition *Trans = audioItem->data; - return 0; + if ( !Trans || !(Trans->flags & AAFI_TRANS_XFADE) ) + return NULL; + + return Trans; } -aafiTransition * aafi_get_fadein( aafiTimelineItem *audioItem ) +aafiTransition * aafi_getFadeIn( aafiAudioClip *audioClip ) { + if ( !audioClip ) { + return NULL; + } + + aafiTimelineItem *audioItem = audioClip->timelineItem; + + if ( !audioItem ) { + return NULL; + } if ( audioItem->prev != NULL && audioItem->prev->type == AAFI_TRANS ) @@ -330,8 +325,17 @@ aafiTransition * aafi_get_fadein( aafiTimelineItem *audioItem ) -aafiTransition * aafi_get_fadeout( aafiTimelineItem *audioItem ) +aafiTransition * aafi_getFadeOut( aafiAudioClip *audioClip ) { + if ( !audioClip ) { + return NULL; + } + + aafiTimelineItem *audioItem = audioClip->timelineItem; + + if ( !audioItem ) { + return NULL; + } if ( audioItem->next != NULL && audioItem->next->type == AAFI_TRANS ) @@ -347,163 +351,321 @@ aafiTransition * aafi_get_fadeout( aafiTimelineItem *audioItem ) -aafiTransition * aafi_get_xfade( aafiTimelineItem *audioItem ) +int aafi_get_clipIndex( aafiAudioClip *audioClip ) { - if ( audioItem->prev != NULL && - audioItem->prev->type == AAFI_TRANS ) - { - aafiTransition *Trans = audioItem->prev->data; + if ( !audioClip ) { + return 0; + } - if ( Trans->flags & AAFI_TRANS_XFADE ) - return Trans; + int index = 0; + struct aafiTimelineItem *timelineItem = NULL; + struct aafiAudioTrack *track = audioClip->track; + + AAFI_foreachTrackItem( track, timelineItem ) { + if ( timelineItem->type == AAFI_AUDIO_CLIP ) { + index++; + } + if ( timelineItem->data == audioClip ) { + return index; + } } - return NULL; + return 0; } -aafiMarker * aafi_newMarker( AAF_Iface *aafi, aafRational_t *editRate, aafPosition_t start, aafPosition_t length, wchar_t *name, wchar_t *comment, uint16_t *(RGBColor[3]) ) -{ - aafiMarker *marker = malloc( sizeof(aafiMarker) ); +aafPosition_t aafi_convertUnit( aafPosition_t value, aafRational_t *valueEditRate, aafRational_t *destEditRate ) { - marker->edit_rate = editRate; - marker->start = start; - marker->length = length; + if ( !valueEditRate || !destEditRate ) { + return value; + } - marker->name = name; - marker->comment = comment; + if ( valueEditRate->numerator == destEditRate->numerator && + valueEditRate->denominator == destEditRate->denominator ) + { + /* same rate, no conversion */ + return value; + } - marker->prev = NULL; - marker->next = NULL; + double valueEditRateFloat = (( valueEditRate->denominator == 0 ) ? 0.0 : ((float)valueEditRate->numerator / (float)valueEditRate->denominator)); + double destEditRateFloat = (( destEditRate->denominator == 0 ) ? 0.0 : ((float)destEditRate->numerator / (float)destEditRate->denominator )); - if ( RGBColor ) { - marker->RGBColor[0] = (*RGBColor)[0]; - marker->RGBColor[1] = (*RGBColor)[1]; - marker->RGBColor[2] = (*RGBColor)[2]; + if ( valueEditRateFloat == 0 ) { + return 0; } - if ( aafi->Markers != NULL ) { + return (aafPosition_t)((double)value * (destEditRateFloat / valueEditRateFloat)); +} - aafiMarker *tmp = aafi->Markers; - for (; tmp != NULL; tmp = tmp->next ) - if ( tmp->next == NULL ) - break; - tmp->next = marker; - marker->prev = marker; +uint64_t aafi_convertUnitUint64( aafPosition_t value, aafRational_t *valueEditRate, aafRational_t *destEditRate ) { + + if ( !valueEditRate || !destEditRate ) { + if ( value < 0 ) { + /* TODO is ULONG_MAX ok for max uint64_t ? */ + return ULONG_MAX; + } + + return (uint64_t)value; } - else { - aafi->Markers = marker; - marker->prev = NULL; + + if ( valueEditRate->numerator == destEditRate->numerator && + valueEditRate->denominator == destEditRate->denominator ) + { + /* same rate, no conversion */ + if ( value < 0 ) { + /* TODO is ULONG_MAX ok for max uint64_t ? */ + return ULONG_MAX; + } + + return (uint64_t)value; } - return marker; + double valueEditRateFloat = (( valueEditRate->denominator == 0 ) ? 0.0 : ((float)valueEditRate->numerator / (float)valueEditRate->denominator)); + double destEditRateFloat = (( destEditRate->denominator == 0 ) ? 0.0 : ((float)destEditRate->numerator / (float)destEditRate->denominator )); + + if ( valueEditRateFloat == 0 ) { + return 0; + } + + return (uint64_t)((double)value * (destEditRateFloat / valueEditRateFloat)); } -void aafi_freeMarkers( aafiMarker **Markers ) -{ - aafiMarker *marker = NULL; - aafiMarker *nextMarker = NULL; +int aafi_removeTimelineItem( AAF_Iface *aafi, aafiTimelineItem *timelineItem ) { - for ( marker = (*Markers); marker != NULL; marker = nextMarker ) { + if ( !timelineItem ) { + return 0; + } - nextMarker = marker->next; + if ( timelineItem->prev != NULL ) { + timelineItem->prev->next = timelineItem->next; + } - if ( marker->name ) - free( marker->name ); + if ( timelineItem->next != NULL ) { + timelineItem->next->prev = timelineItem->prev; + } - if ( marker->comment ) - free( marker->comment ); - free( marker ); + aafiAudioTrack *audioTrack = NULL; + + AAFI_foreachAudioTrack( aafi, audioTrack ) { + if ( audioTrack->timelineItems == timelineItem ) { + audioTrack->timelineItems = timelineItem->next; + } } - *Markers = NULL; + + aafi_freeTimelineItem( timelineItem ); + + return 0; } -aafiTimelineItem * aafi_newTimelineItem( AAF_Iface *aafi, void *track, int itemType ) +int aafi_getAudioEssencePointerChannelCount( aafiAudioEssencePointer *essencePointerList ) { + /* + * If essencePointerList holds a single multichannel essence file and if + * essencePointer->essenceChannel is set, then clip is mono and audio comes + * from essencePointer->essenceChannel of essencePointer.essenceFile. + * + * If essencePointerList holds a single multichannel essence file and if + * essencePointer->essenceChannel is null, then clip is multichannel and + * clip channel count equals essence->channels. + * + * If essencePointerList holds multiple pointers to multiple essence files, + * then each file should be mono and describe a clip channel. Thus, clip + * channel count equals pointers count. + */ + + // if ( !essencePointerList ) { + // return 0; + // } + + int essencePointerCount = 0; + aafiAudioEssencePointer *essencePointer = NULL; + + AAFI_foreachEssencePointer( essencePointerList, essencePointer ) { + essencePointerCount++; + } - aafiTimelineItem *item = NULL; + return ( essencePointerCount > 1 ) ? essencePointerCount : ( essencePointerList->essenceChannel ) ? 1 : essencePointerList->essenceFile->channels; +} - if ( itemType == AAFI_AUDIO_CLIP ) { - item = calloc( sizeof(aafiTimelineItem), sizeof(char) ); - if ( item == NULL ) { - error( "%s.", strerror( errno ) ); - return NULL; +int aafi_applyGainOffset( AAF_Iface *aafi, aafiAudioGain **gain, aafiAudioGain *offset ) +{ + if ( (offset->flags & AAFI_AUDIO_GAIN_MASK) & AAFI_AUDIO_GAIN_VARIABLE ) { + debug( "Variable gain offset is not supported" ); + return -1; + } + + if ( *gain == NULL ) { + + /* + * apply offset as new gain + */ + + debug( "Applying gain to clip as a new gain" ); + + (*gain) = aafi_newAudioGain( aafi, offset->flags & AAFI_AUDIO_GAIN_MASK, offset->flags & AAFI_INTERPOL_MASK, NULL ); + + (*gain)->time = calloc( (uint64_t)offset->pts_cnt, sizeof(aafRational_t) ); + (*gain)->value = calloc( (uint64_t)offset->pts_cnt, sizeof(aafRational_t) ); + + if ( !(*gain)->time || !(*gain)->value ) { + error( "Out of memory" ); + aafi_freeAudioGain( *gain ); + return -1; } + for ( unsigned int i = 0; i < (*gain)->pts_cnt; i++ ) { + (*gain)->value[i].numerator = offset->value[0].numerator; + (*gain)->value[i].denominator = offset->value[0].denominator; + // debug( "Setting (*gain)->value[%i] = %i/%i", + // i, + // (*gain)->value[i].numerator, + // (*gain)->value[i].denominator ); + } + } + else { + + /* + * update existing constant or variable gain + */ + + debug( "Applying gain to clip: %i/%i (%+05.1lf dB) ", + (*gain)->value[0].numerator, + (*gain)->value[0].denominator, + 20 * log10( aafRationalToDouble( (*gain)->value[0] ) ) ); + + for ( unsigned int i = 0; i < (*gain)->pts_cnt; i++ ) { + /* + * most of the time, gain values are made of very high numbers and denominator + * is the same accross all gains in file. Thus, we devide both gain numbers + * by offset denominator, so we fit inside uint32_t. + */ + (*gain)->value[i].numerator = (int32_t)(((int64_t)(*gain)->value[i].numerator * (int64_t)offset->value[0].numerator)/(int64_t)offset->value[0].denominator); + (*gain)->value[i].denominator = (int32_t)(((int64_t)(*gain)->value[i].denominator * (int64_t)offset->value[0].denominator)/(int64_t)offset->value[0].denominator); + // debug( "Setting (*gain)->value[%i] = %i/%i * %i/%i", + // i, + // (*gain)->value[i].numerator, + // (*gain)->value[i].denominator, + // offset->value[0].numerator, + // offset->value[0].denominator ); + } + } + + return 0; +} - item->type = AAFI_AUDIO_CLIP; - item->data = calloc( sizeof(aafiAudioClip), sizeof(char) ); - aafiAudioClip *audioClip = item->data; +aafiAudioTrack * aafi_newAudioTrack( AAF_Iface *aafi ) +{ + aafiAudioTrack *track = calloc( 1, sizeof(aafiAudioTrack) ); - audioClip->track = (aafiAudioTrack*)track; - audioClip->Item = item; + if ( !track ) { + error( "Out of memory" ); + return NULL; } - else if ( itemType == AAFI_VIDEO_CLIP ) { - item = calloc( sizeof(aafiTimelineItem), sizeof(char) ); + track->Audio = aafi->Audio; + track->format = AAFI_TRACK_FORMAT_NOT_SET; + track->next = NULL; + + /* Add to track list */ - if ( item == NULL ) { - error( "%s.", strerror( errno ) ); - return NULL; - } + if ( aafi->Audio->Tracks != NULL ) { + + aafiAudioTrack *tmp = aafi->Audio->Tracks; + + for (; tmp != NULL; tmp = tmp->next ) + if ( tmp->next == NULL ) + break; + + tmp->next = track; + } + else { + aafi->Audio->Tracks = track; + } + return track; +} - item->type = AAFI_VIDEO_CLIP; - item->data = calloc( sizeof(aafiVideoClip), sizeof(char) ); - aafiVideoClip *videoClip = item->data; +aafiVideoTrack * aafi_newVideoTrack( AAF_Iface *aafi ) +{ + aafiVideoTrack *track = calloc( 1, sizeof(aafiVideoTrack) ); - videoClip->track = (aafiVideoTrack*)track; + if ( !track ) { + error( "Out of memory" ); + return NULL; } - else if ( itemType == AAFI_TRANS ) { - item = calloc( sizeof(aafiTimelineItem), sizeof(char) ); + track->Video = aafi->Video; + track->next = NULL; + + /* Add to track list */ - if ( item == NULL ) { - error( "%s.", strerror( errno ) ); - return NULL; - } + if ( aafi->Video->Tracks != NULL ) { + + aafiVideoTrack *tmp = aafi->Video->Tracks; + + for (; tmp != NULL; tmp = tmp->next ) + if ( tmp->next == NULL ) + break; + + tmp->next = track; + } + else { + aafi->Video->Tracks = track; + } + + return track; +} - item->type = AAFI_TRANS; - item->data = calloc( sizeof(aafiTransition), sizeof(char) ); + +aafiTimelineItem * aafi_newTimelineItem( AAF_Iface *aafi, void *track, int itemType, void *data ) +{ + aafiTimelineItem *timelineItem = calloc( 1, sizeof(aafiTimelineItem) ); + + if ( !timelineItem ) { + error( "Out of memory" ); + return NULL; } + timelineItem->type = itemType; + timelineItem->data = data; + if ( itemType == AAFI_AUDIO_CLIP || itemType == AAFI_TRANS ) { if ( track != NULL ) { - /* Add to track's item list */ + /* Add to track's timelineItem list */ - if ( ((aafiAudioTrack*)track)->Items != NULL ) { + if ( ((aafiAudioTrack*)track)->timelineItems != NULL ) { - aafiTimelineItem *tmp = ((aafiAudioTrack*)track)->Items; + aafiTimelineItem *tmp = ((aafiAudioTrack*)track)->timelineItems; for (; tmp != NULL; tmp = tmp->next ) if ( tmp->next == NULL ) break; - tmp->next = item; - item->prev = tmp; + tmp->next = timelineItem; + timelineItem->prev = tmp; } else { - ((aafiAudioTrack*)track)->Items = item; - item->prev = NULL; + ((aafiAudioTrack*)track)->timelineItems = timelineItem; + timelineItem->prev = NULL; } } } @@ -511,162 +673,170 @@ aafiTimelineItem * aafi_newTimelineItem( AAF_Iface *aafi, void *track, int itemT if ( track != NULL ) { - /* Add to track's item list */ + /* Add to track's timelineItem list */ - if ( ((aafiVideoTrack*)track)->Items != NULL ) { + if ( ((aafiVideoTrack*)track)->timelineItems != NULL ) { - aafiTimelineItem *tmp = ((aafiVideoTrack*)track)->Items; + aafiTimelineItem *tmp = ((aafiVideoTrack*)track)->timelineItems; for (; tmp != NULL; tmp = tmp->next ) if ( tmp->next == NULL ) break; - tmp->next = item; - item->prev = tmp; + tmp->next = timelineItem; + timelineItem->prev = tmp; } else { - ((aafiVideoTrack*)track)->Items = item; - item->prev = NULL; + ((aafiVideoTrack*)track)->timelineItems = timelineItem; + timelineItem->prev = NULL; } } } - return item; + return timelineItem; } -int aafi_removeTimelineItem( AAF_Iface *aafi, aafiTimelineItem *item ) { +aafiAudioClip * aafi_newAudioClip( AAF_Iface *aafi, aafiAudioTrack *track ) { - if ( item->prev != NULL ) { - item->prev->next = item->next; - } + aafiAudioClip *audioClip = calloc( 1, sizeof(aafiAudioClip) ); - if ( item->next != NULL ) { - item->next->prev = item->prev; + if ( !audioClip ) { + error( "Out of memory" ); + return NULL; } + audioClip->track = track; + audioClip->timelineItem = aafi_newTimelineItem( aafi, track, AAFI_AUDIO_CLIP, audioClip ); - aafiAudioTrack *audioTrack = NULL; - - foreach_audioTrack( audioTrack, aafi ) { - if ( audioTrack->Items == item ) { - audioTrack->Items = item->next; - } + if ( !audioClip->timelineItem ) { + error( "Could not create new timelineItem" ); + free( audioClip ); + return NULL; } - - aafi_freeTimelineItem( &item ); - - return 0; + return audioClip; } -void aafi_freeAudioGain( aafiAudioGain *gain ) -{ - if ( gain == NULL ) { - return; - } +aafiVideoClip * aafi_newVideoClip( AAF_Iface *aafi, aafiVideoTrack *track ) { + aafiVideoClip *videoClip = calloc( 1, sizeof(aafiVideoClip) ); - if ( gain->time != NULL ) { - free( gain->time ); + if ( !videoClip ) { + error( "Out of memory" ); + return NULL; } - if ( gain->value != NULL ) { - free( gain->value ); + videoClip->track = track; + videoClip->timelineItem = aafi_newTimelineItem( aafi, track, AAFI_VIDEO_CLIP, videoClip ); + + if ( !videoClip->timelineItem ) { + error( "Could not create new timelineItem" ); + free( videoClip ); + return NULL; } - free( gain ); + return videoClip; } -void aafi_freeAudioPan( aafiAudioPan *pan ) -{ - aafi_freeAudioGain( (aafiAudioGain*)pan ); -} - +aafiTransition * aafi_newTransition( AAF_Iface *aafi, aafiAudioTrack *track ) { + aafiTransition *trans = calloc( 1, sizeof(aafiTransition) ); -void aafi_freeAudioClip( aafiAudioClip *audioClip ) -{ - if ( audioClip->gain != NULL ) { - aafi_freeAudioGain( audioClip->gain ); + if ( !trans ) { + error( "Out of memory" ); + return NULL; } - if ( audioClip->automation != NULL ) { - aafi_freeAudioGain( audioClip->automation ); + trans->timelineItem = aafi_newTimelineItem( aafi, track, AAFI_TRANS, trans ); + + if ( !trans->timelineItem ) { + error( "Could not create new timelineItem" ); + free(trans); + return NULL; } - aafi_freeAudioEssencePointer( audioClip->essencePointerList ); + trans->time_a = calloc( 2, sizeof(aafRational_t) ); + trans->value_a = calloc( 2, sizeof(aafRational_t) ); + + if ( !trans->time_a || !trans->value_a ) { + error( "Out of memory" ); + aafi_freeTimelineItem( trans->timelineItem ); + return NULL; + } + + return trans; } -void aafi_freeAudioEssencePointer( aafiAudioEssencePointer *essencePointer ) +aafiMarker * aafi_newMarker( AAF_Iface *aafi, aafRational_t *editRate, aafPosition_t start, aafPosition_t length, char *name, char *comment, uint16_t *(RGBColor[]) ) { - aafiAudioEssencePointer *next = NULL; + aafiMarker *marker = calloc( sizeof(aafiMarker), 1 ); - while ( essencePointer ) { - next = essencePointer->next; - free( essencePointer ); - essencePointer = next; + if ( !marker ) { + error( "Out of memory" ); + return NULL; } -} - + marker->edit_rate = editRate; + marker->start = start; + marker->length = length; -void aafi_freeTimelineItem( aafiTimelineItem **item ) -{ - if ( (*item)->type == AAFI_TRANS ) { - aafi_freeTransition( (aafiTransition*)((*item)->data) ); - free( (*item)->data ); - } - else if ( (*item)->type == AAFI_AUDIO_CLIP ) { - aafi_freeAudioClip( (aafiAudioClip*)((*item)->data) ); - free( (*item)->data ); - } - else if ( (*item)->type == AAFI_VIDEO_CLIP ) { - free( (*item)->data ); - } + marker->name = name; + marker->comment = comment; - free( *item ); + marker->prev = NULL; + marker->next = NULL; - *item = NULL; -} + if ( RGBColor && *RGBColor ) { + marker->RGBColor[0] = (*RGBColor)[0]; + marker->RGBColor[1] = (*RGBColor)[1]; + marker->RGBColor[2] = (*RGBColor)[2]; + } + if ( aafi->Markers != NULL ) { + aafiMarker *tmp = aafi->Markers; -void aafi_freeTimelineItems( aafiTimelineItem **items ) -{ - aafiTimelineItem *item = NULL; - aafiTimelineItem *nextItem = NULL; + for (; tmp != NULL; tmp = tmp->next ) + if ( tmp->next == NULL ) + break; - for ( item = (*items); item != NULL; item = nextItem ) { - nextItem = item->next; - aafi_freeTimelineItem( &item ); + tmp->next = marker; + marker->prev = marker; + } + else { + aafi->Markers = marker; + marker->prev = NULL; } - *items = NULL; + return marker; } -aafiUserComment * aafi_newUserComment( AAF_Iface *aafi, aafiUserComment **CommentList ) +aafiMetaData * aafi_newMetadata( AAF_Iface *aafi, aafiMetaData **CommentList ) { + if ( !CommentList ) { + return NULL; + } - aafiUserComment *UserComment = calloc( sizeof(aafiUserComment), 1 ); + aafiMetaData *UserComment = calloc( 1, sizeof(aafiMetaData) ); - if ( UserComment == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !UserComment ) { + error( "Out of memory" ); return NULL; } - if ( CommentList != NULL ) { + if ( *CommentList != NULL ) { UserComment->next = *CommentList; *CommentList = UserComment; } @@ -680,153 +850,153 @@ aafiUserComment * aafi_newUserComment( AAF_Iface *aafi, aafiUserComment **Commen -void aafi_freeUserComments( aafiUserComment **CommentList ) +aafiAudioEssencePointer * aafi_newAudioEssencePointer( AAF_Iface *aafi, aafiAudioEssencePointer **list, aafiAudioEssenceFile *audioEssenceFile, uint32_t *essenceChannelNum ) { - aafiUserComment *UserComment = *CommentList; - aafiUserComment *tmp = NULL; + aafiAudioEssencePointer * essencePointer = calloc( 1, sizeof(aafiAudioEssencePointer) ); - while( UserComment != NULL ) { + if ( !essencePointer ) { + error( "Out of memory" ); + return NULL; + } - tmp = UserComment; - UserComment = UserComment->next; + essencePointer->aafi = aafi; + essencePointer->essenceFile = audioEssenceFile; + essencePointer->essenceChannel = ( essenceChannelNum ) ? *essenceChannelNum : 0; - if ( tmp->name != NULL ) { - free( tmp->name ); - } - if ( tmp->text != NULL ) { - free( tmp->text ); + if ( *list ) { + aafiAudioEssencePointer *last = *list; + while ( last->next != NULL ) { + last = last->next; } + last->next = essencePointer; + } + else { + *list = essencePointer; - free( tmp ); + essencePointer->aafiNext = aafi->Audio->essencePointerList; + aafi->Audio->essencePointerList = essencePointer; } - *CommentList = NULL; + return *list; } -void aafi_freeTransition( aafiTransition *Transition ) +aafiAudioEssenceFile * aafi_newAudioEssence( AAF_Iface *aafi ) { - if ( Transition->value_a != NULL ) { - free( Transition->value_a ); - } + aafiAudioEssenceFile * audioEssenceFile = calloc( 1, sizeof(aafiAudioEssenceFile) ); - if ( Transition->value_b != NULL ) { - free( Transition->value_b ); + if ( !audioEssenceFile ) { + error( "Out of memory" ); + goto err; } - if ( Transition->time_a != NULL ) { - free( Transition->time_a ); - } + audioEssenceFile->samplerateRational = malloc( sizeof(aafRational_t) ); - if ( Transition->time_b != NULL ) { - free( Transition->time_b ); + if ( !audioEssenceFile->samplerateRational ) { + error( "Out of memory" ); + goto err; } -} + audioEssenceFile->samplerateRational->numerator = 1; + audioEssenceFile->samplerateRational->denominator = 1; + audioEssenceFile->next = aafi->Audio->essenceFiles; -aafiAudioTrack * aafi_newAudioTrack( AAF_Iface *aafi ) -{ - aafiAudioTrack *track = calloc( sizeof(aafiAudioTrack), sizeof(unsigned char) ); + aafi->Audio->essenceFiles = audioEssenceFile; + aafi->Audio->essenceCount++; - if ( track == NULL ) { - error( "%s.", strerror( errno ) ); - return NULL; - } + return audioEssenceFile; - track->Audio = aafi->Audio; - track->format = AAFI_TRACK_FORMAT_NOT_SET; - track->next = NULL; +err: + if ( audioEssenceFile ) { + free( audioEssenceFile->samplerateRational ); + free( audioEssenceFile ); + } - /* Add to track list */ + return NULL; +} - if ( aafi->Audio->Tracks != NULL ) { - aafiAudioTrack *tmp = aafi->Audio->Tracks; - for (; tmp != NULL; tmp = tmp->next ) - if ( tmp->next == NULL ) - break; +aafiVideoEssence * aafi_newVideoEssence( AAF_Iface *aafi ) +{ + aafiVideoEssence * videoEssenceFile = calloc( 1, sizeof(aafiVideoEssence) ); - tmp->next = track; - } - else { - aafi->Audio->Tracks = track; + if ( !videoEssenceFile ) { + error( "Out of memory" ); + return NULL; } - return track; + videoEssenceFile->next = aafi->Video->essenceFiles; + + aafi->Video->essenceFiles = videoEssenceFile; + + return videoEssenceFile; } -void aafi_freeAudioTracks( aafiAudioTrack **tracks ) +aafiAudioGain * aafi_newAudioGain( AAF_Iface *aafi, enum aafiAudioGain_e type, enum aafiInterpolation_e interpol, aafRational_t *singleValue ) { - if ( *(tracks) == NULL ) { - return; - } + aafiAudioGain *Gain = calloc( 1, sizeof(aafiAudioGain) ); - aafiAudioTrack *track = NULL; - aafiAudioTrack *nextTrack = NULL; + if ( !Gain ) { + error( "Out of memory" ); + return NULL; + } - for ( track = (*tracks); track != NULL; track = nextTrack ) { + Gain->flags |= type; + Gain->flags |= interpol; - nextTrack = track->next; + if ( singleValue ) { + Gain->pts_cnt = 1; + Gain->value = calloc( 1, sizeof(aafRational_t) ); - if ( track->name != NULL ) { - free( track->name ); + if ( !Gain->value ) { + error( "Out of memory" ); + free( Gain ); + return NULL; } - if ( track->gain != NULL ) { - aafi_freeAudioGain( track->gain ); - } + memcpy( &Gain->value[0], singleValue, sizeof(aafRational_t) ); + } - if ( track->pan != NULL ) { - aafi_freeAudioPan( track->pan ); - } + return Gain; +} - if ( track->Items != NULL ) { - aafi_freeTimelineItems( &(track->Items) ); - } - free( track ); - } - *tracks = NULL; +aafiAudioGain * aafi_newAudioPan( AAF_Iface *aafi, enum aafiAudioGain_e type, enum aafiInterpolation_e interpol, aafRational_t *singleValue ) +{ + return aafi_newAudioGain( aafi, type, interpol, singleValue ); } -aafiVideoTrack * aafi_newVideoTrack( AAF_Iface *aafi ) +void aafi_freeAudioTracks( aafiAudioTrack **tracks ) { - aafiVideoTrack *track = calloc( sizeof(aafiVideoTrack), sizeof(unsigned char) ); - - if ( track == NULL ) { - error( "%s.", strerror( errno ) ); - return NULL; + if ( !tracks || !(*tracks) ) { + return; } - track->Video = aafi->Video; - track->next = NULL; - - /* Add to track list */ + aafiAudioTrack *track = NULL; + aafiAudioTrack *nextTrack = NULL; - if ( aafi->Video->Tracks != NULL ) { + for ( track = (*tracks); track != NULL; track = nextTrack ) { - aafiVideoTrack *tmp = aafi->Video->Tracks; + nextTrack = track->next; - for (; tmp != NULL; tmp = tmp->next ) - if ( tmp->next == NULL ) - break; + free( track->name ); + aafi_freeAudioGain( track->gain ); + aafi_freeAudioPan( track->pan ); + aafi_freeTimelineItems( &track->timelineItems ); - tmp->next = track; - } - else { - aafi->Video->Tracks = track; + free( track ); } - return track; + *tracks = NULL; } @@ -844,13 +1014,8 @@ void aafi_freeVideoTracks( aafiVideoTrack **tracks ) nextTrack = track->next; - if ( track->name != NULL ) { - free( track->name ); - } - - if ( track->Items != NULL ) { - aafi_freeTimelineItems( &(track->Items) ); - } + free( track->name ); + aafi_freeTimelineItems( &track->timelineItems ); free( track ); } @@ -859,187 +1024,204 @@ void aafi_freeVideoTracks( aafiVideoTrack **tracks ) } - -aafiAudioEssence * aafi_newAudioEssence( AAF_Iface *aafi ) +void aafi_freeTimelineItems( aafiTimelineItem **timelineItems ) { - aafiAudioEssence * audioEssence = calloc( sizeof(aafiAudioEssence), sizeof(char) ); + aafiTimelineItem *timelineItem = NULL; + aafiTimelineItem *nextItem = NULL; - if ( audioEssence == NULL ) { - error( "%s.", strerror( errno ) ); - return NULL; + for ( timelineItem = (*timelineItems); timelineItem != NULL; timelineItem = nextItem ) { + nextItem = timelineItem->next; + aafi_freeTimelineItem( timelineItem ); } - audioEssence->samplerateRational = malloc( sizeof(aafRational_t) ); + *timelineItems = NULL; +} - if ( audioEssence->samplerateRational == NULL ) { - return NULL; - } - audioEssence->samplerateRational->numerator = 1; - audioEssence->samplerateRational->denominator = 1; - audioEssence->next = aafi->Audio->Essences; +void aafi_freeTimelineItem( aafiTimelineItem *timelineItem ) +{ + if ( !timelineItem ) { + return; + } - aafi->Audio->Essences = audioEssence; + if ( timelineItem->type == AAFI_TRANS ) { + aafi_freeTransition( timelineItem->data ); + } + else if ( timelineItem->type == AAFI_AUDIO_CLIP ) { + aafi_freeAudioClip( timelineItem->data ); + } + else if ( timelineItem->type == AAFI_VIDEO_CLIP ) { + free( timelineItem->data ); + } - return audioEssence; + free( timelineItem ); } -aafiAudioEssencePointer * aafi_newAudioEssencePointer( AAF_Iface *aafi, aafiAudioEssencePointer **list, aafiAudioEssence *audioEssence, uint32_t *essenceChannelNum ) +void aafi_freeAudioClip( aafiAudioClip *audioClip ) { - aafiAudioEssencePointer * essencePointer = calloc( sizeof(aafiAudioEssencePointer), sizeof(char) ); - - if ( essencePointer == NULL ) { - error( "%s.", strerror( errno ) ); - return NULL; + if ( !audioClip ) { + return; } - essencePointer->aafi = aafi; - essencePointer->essence = audioEssence; - essencePointer->essenceChannel = ( essenceChannelNum ) ? *essenceChannelNum : 0; - + free( audioClip->subClipName ); - if ( *list ) { - aafiAudioEssencePointer *last = *list; - while ( last->next != NULL ) { - last = last->next; - } - last->next = essencePointer; - } - else { - *list = essencePointer; + aafi_freeAudioGain( audioClip->gain ); + aafi_freeAudioGain( audioClip->automation ); + aafi_freeMetadata( &(audioClip->metadata) ); - essencePointer->aafiNext = aafi->Audio->essencePointerList; - aafi->Audio->essencePointerList = essencePointer; - } + aafi_freeAudioEssencePointer( audioClip->essencePointerList ); - return *list; + free( audioClip ); } -void aafi_freeAudioEssences( aafiAudioEssence **audioEssence ) +void aafi_freeTransition( aafiTransition *Transition ) { - if ( *(audioEssence) == NULL ) { + if ( !Transition ) { return; } - aafiAudioEssence *nextAudioEssence = NULL; + free( Transition->value_a ); + free( Transition->value_b ); + free( Transition->time_a ); + free( Transition->time_b ); - for (; (*audioEssence) != NULL; *audioEssence = nextAudioEssence ) { + free( Transition ); +} - nextAudioEssence = (*audioEssence)->next; - if ( (*audioEssence)->original_file_path != NULL ) { - free( (*audioEssence)->original_file_path ); - } - if ( (*audioEssence)->usable_file_path != NULL ) { - free( (*audioEssence)->usable_file_path ); - } +void aafi_freeMarkers( aafiMarker **Markers ) +{ + aafiMarker *marker = NULL; + aafiMarker *nextMarker = NULL; - if ( (*audioEssence)->file_name != NULL ) { - free( (*audioEssence)->file_name ); - } + for ( marker = (*Markers); marker != NULL; marker = nextMarker ) { - if ( (*audioEssence)->unique_file_name != NULL ) { - free( (*audioEssence)->unique_file_name ); - } + nextMarker = marker->next; - if ( (*audioEssence)->samplerateRational != NULL ) { - free( (*audioEssence)->samplerateRational ); - } + free( marker->name ); + free( marker->comment ); - free( *audioEssence ); + free( marker ); } - *audioEssence = NULL; + *Markers = NULL; } -aafiVideoEssence * aafi_newVideoEssence( AAF_Iface *aafi ) + +void aafi_freeMetadata( aafiMetaData **CommentList ) { - aafiVideoEssence * videoEssence = calloc( sizeof(aafiVideoEssence), sizeof(char) ); + aafiMetaData *UserComment = *CommentList; + aafiMetaData *tmp = NULL; - if ( videoEssence == NULL ) { - error( "%s.", strerror( errno ) ); - return NULL; - } + while( UserComment != NULL ) { - videoEssence->next = aafi->Video->Essences; + tmp = UserComment; + UserComment = UserComment->next; - aafi->Video->Essences = videoEssence; + free( tmp->name ); + free( tmp->text ); - return videoEssence; + free( tmp ); + } + + *CommentList = NULL; } -void aafi_freeVideoEssences( aafiVideoEssence **videoEssence ) + +void aafi_freeAudioEssencePointer( aafiAudioEssencePointer *essencePointer ) { - if ( *(videoEssence) == NULL ) { - return; + aafiAudioEssencePointer *next = NULL; + + while ( essencePointer ) { + next = essencePointer->next; + free( essencePointer ); + essencePointer = next; } +} - aafiVideoEssence *nextVideoEssence = NULL; - for (; (*videoEssence) != NULL; *videoEssence = nextVideoEssence ) { - nextVideoEssence = (*videoEssence)->next; +void aafi_freeAudioEssences( aafiAudioEssenceFile **audioEssenceFile ) +{ + if ( *(audioEssenceFile) == NULL ) { + return; + } - if ( (*videoEssence)->original_file_path != NULL ) { - free( (*videoEssence)->original_file_path ); - } + aafiAudioEssenceFile *nextAudioEssence = NULL; - if ( (*videoEssence)->usable_file_path != NULL ) { - free( (*videoEssence)->usable_file_path ); - } + for (; (*audioEssenceFile) != NULL; *audioEssenceFile = nextAudioEssence ) { - if ( (*videoEssence)->file_name != NULL ) { - free( (*videoEssence)->file_name ); - } + nextAudioEssence = (*audioEssenceFile)->next; - if ( (*videoEssence)->unique_file_name != NULL ) { - free( (*videoEssence)->unique_file_name ); - } + free( (*audioEssenceFile)->original_file_path ); + free( (*audioEssenceFile)->usable_file_path ); + free( (*audioEssenceFile)->name ); + free( (*audioEssenceFile)->unique_name ); + free( (*audioEssenceFile)->samplerateRational ); - free( *videoEssence ); + aafi_freeMetadata( &((*audioEssenceFile)->metadata) ); + + free( *audioEssenceFile ); } - *videoEssence = NULL; + *audioEssenceFile = NULL; } -int aafi_getAudioEssencePointerChannelCount( aafiAudioEssencePointer *essencePointerList ) +void aafi_freeVideoEssences( aafiVideoEssence **videoEssenceFile ) { - /* - * If essencePointerList holds a single multichannel essence file and if - * essencePointer->essenceChannel is set, then clip is mono and audio comes - * from essencePointer->essenceChannel of essencePointer->essence file. - * - * If essencePointerList holds a single multichannel essence file and if - * essencePointer->essenceChannel is null, then clip is multichannel and - * clip channel count equals essence->channels. - * - * If essencePointerList holds multiple pointers to multiple essence files, - * then each file should be mono and describe a clip channel. Thus, clip - * channel count equals pointers count. - */ + if ( *(videoEssenceFile) == NULL ) { + return; + } - int essencePointerCount = 0; - aafiAudioEssencePointer *essencePointer = NULL; + aafiVideoEssence *nextVideoEssence = NULL; - AAFI_foreachAudioEssencePointer( essencePointer, essencePointerList ) { - essencePointerCount++; + for (; (*videoEssenceFile) != NULL; *videoEssenceFile = nextVideoEssence ) { + + nextVideoEssence = (*videoEssenceFile)->next; + + free( (*videoEssenceFile)->original_file_path ); + free( (*videoEssenceFile)->usable_file_path ); + free( (*videoEssenceFile)->name ); + free( (*videoEssenceFile)->unique_name ); + + free( *videoEssenceFile ); } - return ( essencePointerCount > 1 ) ? essencePointerCount : ( essencePointerList->essenceChannel ) ? 1 : essencePointerList->essence->channels; + *videoEssenceFile = NULL; } +void aafi_freeAudioGain( aafiAudioGain *gain ) +{ + if ( gain == NULL ) { + return; + } + + free( gain->time ); + free( gain->value ); + + free( gain ); +} + + + +void aafi_freeAudioPan( aafiAudioPan *pan ) +{ + aafi_freeAudioGain( (aafiAudioGain*)pan ); +} + + /** * @} */ diff --git a/src/AAFIface/MediaComposer.c b/src/AAFIface/MediaComposer.c new file mode 100644 index 0000000..267fcc2 --- /dev/null +++ b/src/AAFIface/MediaComposer.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 Adrien Gesta-Fline + * + * This file is part of libAAF. + * + * 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 + + +#define debug( ... ) \ + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) + +#define warning( ... ) \ + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) + +#define error( ... ) \ + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) + + + +int mediaComposer_AAF( struct AAF_Iface *aafi ) +{ + int probe = 0; + + if ( aafi->aafd->Identification.CompanyName && strncmp( aafi->aafd->Identification.CompanyName, "Avid Technology, Inc.", strlen( "Avid Technology, Inc." ) ) == 0 ) { + probe++; + } + + if ( aafi->aafd->Identification.ProductName && strncmp( aafi->aafd->Identification.ProductName, "Avid Media Composer", strlen( "Avid Media Composer" ) ) == 0 ) { + probe++; + } + + if ( probe == 2 ) { + return 1; + } + + return 0; +} diff --git a/src/AAFIface/ProTools.c b/src/AAFIface/ProTools.c index 467167b..6e112b3 100644 --- a/src/AAFIface/ProTools.c +++ b/src/AAFIface/ProTools.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -24,65 +24,54 @@ #include -#define PROTOOLS_CLIP_NAME_FADE_EN_LEN 5 // +1 -#define PROTOOLS_CLIP_NAME_FADE_DE_LEN 5 // +1 -#define PROTOOLS_CLIP_NAME_FADE_JA_LEN 5 // +1 -#define PROTOOLS_CLIP_NAME_FADE_FR_LEN 6 // +1 -#define PROTOOLS_CLIP_NAME_FADE_ES_LEN 8 // +1 -#define PROTOOLS_CLIP_NAME_FADE_ZH_CN_LEN 3 // +1 -#define PROTOOLS_CLIP_NAME_FADE_ZH_TW_LEN 3 // +1 -#define PROTOOLS_CLIP_NAME_FADE_KO_LEN 3 // +1 - -#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN_LEN 20 // +1 -#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE_LEN 24 // +1 -#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES_LEN 32 // +1 -#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR_LEN 33 // +1 -#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA_LEN 8 // +1 -#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN_LEN 6 // +1 -#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW_LEN 6 // +1 -#define PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO_LEN 11 // +1 - /* English : "Fade " (Same as JA and DE) */ -static const wchar_t PROTOOLS_CLIP_NAME_FADE_EN[] = L"\x0046\x0061\x0064\x0065\x0020\x0000"; -/* German : "Fade " (Same as JA and EN) */ -// static const wchar_t PROTOOLS_CLIP_NAME_FADE_DE[] = L"\x0046\x0061\x0064\x0065\x0020\x0000"; -/* Japanese : "Fade " (Same as EN and DE) */ -// static const wchar_t PROTOOLS_CLIP_NAME_FADE_JA[] = L"\x0046\x0061\x0064\x0065\x0020\x0000"; +static const char PROTOOLS_CLIP_NAME_FADE_EN[] = "\x46\x61\x64\x65\x20"; /* French : "Fondu " */ -static const wchar_t PROTOOLS_CLIP_NAME_FADE_FR[] = L"\x0046\x006f\x006e\x0064\x0075\x0020\x0000"; +static const char PROTOOLS_CLIP_NAME_FADE_FR[] = "\x46\x6f\x6e\x64\x75\x20"; /* Spanish : "Fundido" */ -static const wchar_t PROTOOLS_CLIP_NAME_FADE_ES[] = L"\x0046\x0075\x006e\x0064\x0069\x0064\x006f\x0020\x0000"; +static const char PROTOOLS_CLIP_NAME_FADE_ES[] = "\x46\x75\x6e\x64\x69\x64\x6f\x20"; +/* Korean : "페이드" */ +static const char PROTOOLS_CLIP_NAME_FADE_KO[] = "\xed\x8e\x98\xec\x9d\xb4\xeb\x93\x9c"; /* Chinese (S) : "淡变 " */ -static const wchar_t PROTOOLS_CLIP_NAME_FADE_ZH_CN[] = L"\x6de1\x53d8\x0020\x0000"; +static const char PROTOOLS_CLIP_NAME_FADE_ZH_CN[] = "\xe6\xb7\xa1\xe5\x8f\x98\x20"; /* Chinese (T) : "淡變 " */ -static const wchar_t PROTOOLS_CLIP_NAME_FADE_ZH_TW[] = L"\x6de1\x8b8a\x0020\x0000"; -/* Korean : "페이드" */ -static const wchar_t PROTOOLS_CLIP_NAME_FADE_KO[] = L"\xd398\xc774\xb4dc\x0000"; +static const char PROTOOLS_CLIP_NAME_FADE_ZH_TW[] = "\xe6\xb7\xa1\xe8\xae\x8a\x20"; /* English : "Sample accurate edit" */ -static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN[] = L"\x0053\x0061\x006d\x0070\x006c\x0065\x0020\x0061\x0063\x0063\x0075\x0072\x0061\x0074\x0065\x0020\x0065\x0064\x0069\x0074\x0000"; +static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN[] = "\x53\x61\x6d\x70\x6c\x65\x20\x61\x63\x63\x75\x72\x61\x74\x65\x20\x65\x64\x69\x74"; /* German : "Samplegenaue Bearbeitung" */ -static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE[] = L"\x0053\x0061\x006d\x0070\x006c\x0065\x0067\x0065\x006e\x0061\x0075\x0065\x0020\x0042\x0065\x0061\x0072\x0062\x0065\x0069\x0074\x0075\x006e\x0067\x0000"; +static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE[] = "\x53\x61\x6d\x70\x6c\x65\x67\x65\x6e\x61\x75\x65\x20\x42\x65\x61\x72\x62\x65\x69\x74\x75\x6e\x67"; /* Spanish : "Edición con precisión de muestra" */ -static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES[] = L"\x0045\x0064\x0069\x0063\x0069\x00f3\x006e\x0020\x0063\x006f\x006e\x0020\x0070\x0072\x0065\x0063\x0069\x0073\x0069\x00f3\x006e\x0020\x0064\x0065\x0020\x006d\x0075\x0065\x0073\x0074\x0072\x0061\x0000"; +static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES[] = "\x45\x64\x69\x63\x69\xc3\xb3\x6e\x20\x63\x6f\x6e\x20\x70\x72\x65\x63\x69\x73\x69\xc3\xb3\x6e\x20\x64\x65\x20\x6d\x75\x65\x73\x74\x72\x61"; /* French : "Modification à l'échantillon près" */ -static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR[] = L"\x004d\x006f\x0064\x0069\x0066\x0069\x0063\x0061\x0074\x0069\x006f\x006e\x0020\x00e0\x0020\x006c\x0027\x00e9\x0063\x0068\x0061\x006e\x0074\x0069\x006c\x006c\x006f\x006e\x0020\x0070\x0072\x00e8\x0073\x0000"; +static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR[] = "\x4d\x6f\x64\x69\x66\x69\x63\x61\x74\x69\x6f\x6e\x20\xc3\xa0\x20\x6c\x27\xc3\xa9\x63\x68\x61\x6e\x74\x69\x6c\x6c\x6f\x6e\x20\x70\x72\xc3\xa8\x73"; /* Japanese : "サンプル精度編集" */ -static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA[] = L"\x30b5\x30f3\x30d7\x30eb\x7cbe\x5ea6\x7de8\x96c6\x0000"; +static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA[] = "\xe3\x82\xb5\xe3\x83\xb3\xe3\x83\x97\xe3\x83\xab\xe7\xb2\xbe\xe5\xba\xa6\xe7\xb7\xa8\xe9\x9b\x86"; +/* Korean : "샘플 단위 정밀 편집" */ +static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO[] = "\xec\x83\x98\xed\x94\x8c\x20\xeb\x8b\xa8\xec\x9c\x84\x20\xec\xa0\x95\xeb\xb0\x80\x20\xed\x8e\xb8\xec\xa7\x91"; /* Chinese (S) : "精确采样编辑" */ -static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN[] = L"\x7cbe\x786e\x91c7\x6837\x7f16\x8f91\x0000"; +static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN[] = "\xe7\xb2\xbe\xe7\xa1\xae\xe9\x87\x87\xe6\xa0\xb7\xe7\xbc\x96\xe8\xbe\x91"; /* Chinese (T) : "精確取樣編輯" */ -static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW[] = L"\x7cbe\x78ba\x53d6\x6a23\x7de8\x8f2f\x0000"; -/* Korean : "샘플 단위 정밀 편집" */ -static const wchar_t PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO[] = L"\xc0d8\xd50c\x0020\xb2e8\xc704\x0020\xc815\xbc00\x0020\xd3b8\xc9d1\x0000"; +static const char PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW[] = "\xe7\xb2\xbe\xe7\xa2\xba\xe5\x8f\x96\xe6\xa8\xa3\xe7\xb7\xa8\xe8\xbc\xaf"; + + +#define debug( ... ) \ + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) +#define warning( ... ) \ + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) +#define error( ... ) \ + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) -static int is_rendered_fade( const wchar_t *clipName ); -static int is_sample_accurate_edit( const wchar_t *clipName ); -static int replace_clipfade_with_fade( AAF_Iface *aafi, aafiTimelineItem *Item ); + +static int is_rendered_fade( const char *clipName ); +static int is_sample_accurate_edit( const char *clipName ); +static int remove_sampleAccurateEditClip( AAF_Iface *aafi, aafiAudioTrack *audioTrack, aafiTimelineItem *saeItem ); +static int replace_clipFade( AAF_Iface *aafi, aafiAudioTrack *audioTrack, aafiTimelineItem *fadeItem ); + @@ -90,17 +79,17 @@ int protools_AAF( struct AAF_Iface *aafi ) { int probe = 0; - /* TODO: CompanyName is "Digidesign, Inc." in ProTools 10.3.10.613 AAF, but what about since ? */ + /* NOTE: CompanyName is "Digidesign, Inc." at least since ProTools 10.3.10.613, and still today */ - // if ( aafi->aafd->Identification.CompanyName && wcscmp( aafi->aafd->Identification.CompanyName, L"Digidesign, Inc." ) == 0 ) { - // probe++; - // } + if ( aafi->aafd->Identification.CompanyName && strcmp( aafi->aafd->Identification.CompanyName, "Digidesign, Inc." ) == 0 ) { + probe++; + } - if ( aafi->aafd->Identification.ProductName && wcscmp( aafi->aafd->Identification.ProductName, L"ProTools" ) == 0 ) { + if ( aafi->aafd->Identification.ProductName && strcmp( aafi->aafd->Identification.ProductName, "ProTools" ) == 0 ) { probe++; } - if ( probe == 1 ) { + if ( probe == 2 ) { return 1; } @@ -108,128 +97,294 @@ int protools_AAF( struct AAF_Iface *aafi ) } -static int is_rendered_fade( const wchar_t *clipName ) { + +static int is_rendered_fade( const char *clipName ) { return \ - ( memcmp( clipName, PROTOOLS_CLIP_NAME_FADE_EN, PROTOOLS_CLIP_NAME_FADE_EN_LEN ) == 0 ) || - ( memcmp( clipName, PROTOOLS_CLIP_NAME_FADE_ES, PROTOOLS_CLIP_NAME_FADE_ES_LEN ) == 0 ) || - ( memcmp( clipName, PROTOOLS_CLIP_NAME_FADE_FR, PROTOOLS_CLIP_NAME_FADE_FR_LEN ) == 0 ) || - ( memcmp( clipName, PROTOOLS_CLIP_NAME_FADE_ZH_CN, PROTOOLS_CLIP_NAME_FADE_ZH_CN_LEN ) == 0 ) || - ( memcmp( clipName, PROTOOLS_CLIP_NAME_FADE_ZH_TW, PROTOOLS_CLIP_NAME_FADE_ZH_TW_LEN ) == 0 ) || - ( memcmp( clipName, PROTOOLS_CLIP_NAME_FADE_KO, PROTOOLS_CLIP_NAME_FADE_KO_LEN ) == 0 ); + ( strcmp( clipName, PROTOOLS_CLIP_NAME_FADE_EN ) == 0 ) || + ( strcmp( clipName, PROTOOLS_CLIP_NAME_FADE_ES ) == 0 ) || + ( strcmp( clipName, PROTOOLS_CLIP_NAME_FADE_FR ) == 0 ) || + ( strcmp( clipName, PROTOOLS_CLIP_NAME_FADE_ZH_CN ) == 0 ) || + ( strcmp( clipName, PROTOOLS_CLIP_NAME_FADE_ZH_TW ) == 0 ) || + ( strcmp( clipName, PROTOOLS_CLIP_NAME_FADE_KO ) == 0 ); } -static int is_sample_accurate_edit( const wchar_t *clipName ) { +static int is_sample_accurate_edit( const char *clipName ) { return \ - ( memcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN_LEN ) == 0 ) || - ( memcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE_LEN ) == 0 ) || - ( memcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES_LEN ) == 0 ) || - ( memcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR_LEN ) == 0 ) || - ( memcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA_LEN ) == 0 ) || - ( memcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN_LEN ) == 0 ) || - ( memcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW_LEN ) == 0 ) || - ( memcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO_LEN ) == 0 ); + ( strcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_EN ) == 0 ) || + ( strcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_DE ) == 0 ) || + ( strcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ES ) == 0 ) || + ( strcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_FR ) == 0 ) || + ( strcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_JA ) == 0 ) || + ( strcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_CN ) == 0 ) || + ( strcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_ZH_TW ) == 0 ) || + ( strcmp( clipName, PROTOOLS_CLIP_NAME_SAMPLE_ACCURATE_EDIT_KO ) == 0 ); } -static int replace_clipfade_with_fade( AAF_Iface *aafi, aafiTimelineItem *Item ) { +static int remove_sampleAccurateEditClip( AAF_Iface *aafi, aafiAudioTrack *audioTrack, aafiTimelineItem *saeItem ) { - if ( Item->type != AAFI_AUDIO_CLIP ) { - return -1; - } + /* + * Note: In this function, we assume we need to expand a clip to remove an + * attached sample accurate edit. TODO: Ensure it's always possible with ProTools + */ + aafiAudioClip *saeClip = saeItem->data; - aafiAudioClip *audioClip = (aafiAudioClip*)Item->data; + if ( saeItem->prev ) { + if ( saeItem->prev->type == AAFI_AUDIO_CLIP ) { - aafPosition_t currentpos = audioClip->pos; - aafPosition_t currentlen = audioClip->len; + aafiAudioClip *leftClip = saeItem->prev->data; + if ( saeClip->pos == (leftClip->pos + leftClip->len) ) { + aafPosition_t essenceLength = aafi_convertUnit( leftClip->essencePointerList->essenceFile->length, leftClip->essencePointerList->essenceFile->samplerateRational, leftClip->track->edit_rate ); - aafiTimelineItem *transItem = calloc( sizeof(aafiTimelineItem) + sizeof(aafiTransition), sizeof(char) ); + if ( (essenceLength - leftClip->essence_offset - leftClip->len) >= saeClip->len ) { - memset( transItem, 0x00, sizeof(aafiTimelineItem) + sizeof(aafiTransition) ); + debug( "Removing SAE \"%s\" : left clip \"%s\" goes from length %"PRIi64" to %"PRIi64, + saeClip->essencePointerList->essenceFile->unique_name, + leftClip->essencePointerList->essenceFile->unique_name, + leftClip->len, + leftClip->len+saeClip->len ); - transItem->type = AAFI_TRANS; - transItem->next = NULL; - transItem->prev = NULL; + leftClip->len += saeClip->len; - transItem->data = calloc( sizeof(aafiTransition), sizeof(char) ); + aafi_removeTimelineItem( aafi, saeItem ); - aafiTransition *trans = transItem->data; + audioTrack->clipCount--; + return 1; + } + // else { + // warning( L"Can't remove SAE \"%s\" : left clip \"%s\" has not enough right handle : %lu but %lu is required", + // saeClip->essencePointerList->essenceFile->unique_name, + // leftClip->essencePointerList->essenceFile->unique_name, + // (essenceLength - leftClip->essence_offset - leftClip->len), + // saeClip->len ); + // } + } + } + } - trans->len = audioClip->len; - trans->flags = AAFI_INTERPOL_NONE; + if ( saeItem->next ) { + if ( saeItem->next->type == AAFI_AUDIO_CLIP ) { + aafiAudioClip *rightClip = saeItem->next->data; + if ( (saeClip->pos + saeClip->len) == rightClip->pos ) { - // debug( "%ls", audioClip->Essence->unique_file_name ); + if ( rightClip->essence_offset >= saeClip->len ) { - aafiAudioClip *prevClip = NULL; - aafiAudioClip *nextClip = NULL; + debug( "Removing SAE \"%s\" : right clip \"%s\" goes from length: %"PRIi64" to %"PRIi64", pos: %"PRIi64" to %"PRIi64", source offset: %"PRIi64" to %"PRIi64, + saeClip->essencePointerList->essenceFile->unique_name, + rightClip->essencePointerList->essenceFile->unique_name, + rightClip->len, + rightClip->len+saeClip->len, + rightClip->pos, + rightClip->pos-saeClip->len, + rightClip->essence_offset, + rightClip->essence_offset-saeClip->len ); - if ( Item->prev != NULL ) { - if ( Item->prev->type == AAFI_AUDIO_CLIP ) { - prevClip = (aafiAudioClip*)Item->prev->data; + rightClip->pos -= saeClip->len; + rightClip->len += saeClip->len; + rightClip->essence_offset -= saeClip->len; - // debug( "PREVIOUS POS %lu", prevClip->pos + prevClip->len ); - // debug( "CURENT POS %lu", currentpos ); + aafi_removeTimelineItem( aafi, saeItem ); - if ( prevClip->pos + prevClip->len < currentpos - 1 ) { - prevClip = NULL; + audioTrack->clipCount--; + return 1; + } + // else { + // warning( L"Can't remove SAE \"%s\" : right clip \"%s\" has not enough left handle : %lu but %lu is required", + // saeClip->essencePointerList->essenceFile->unique_name, + // rightClip->essencePointerList->essenceFile->unique_name, + // rightClip->essence_offset, + // saeClip->len ); + // } } } } - if ( Item->next != NULL ) { - if ( Item->next->type == AAFI_AUDIO_CLIP ) { - nextClip = (aafiAudioClip*)Item->next->data; + return 0; +} - if ( is_sample_accurate_edit( nextClip->essencePointerList->essence->file_name ) ) { - if ( Item->next->next != NULL ) { - nextClip = (aafiAudioClip*)Item->next->next->data; - // debug( "NEXT POS %lu", nextClip->pos ); - // debug( "CURENT POS %lu", currentpos + currentlen ); - if ( nextClip->pos != currentpos + currentlen + 1 ) { - nextClip = NULL; +static int replace_clipFade( AAF_Iface *aafi, aafiAudioTrack *audioTrack, aafiTimelineItem *fadeItem ) { + + aafiAudioClip *fadeClip = fadeItem->data; + + aafiTimelineItem *prevItem1 = fadeItem->prev; + aafiTimelineItem *prevItem2 = (prevItem1 && prevItem1->prev) ? prevItem1->prev : NULL; + + aafiTimelineItem *nextItem1 = fadeItem->next; + aafiTimelineItem *nextItem2 = (nextItem1 && nextItem1->next) ? nextItem1->next : NULL; + + aafiAudioClip *prevClip = NULL; + aafiAudioClip *nextClip = NULL; + + + if ( prevItem1 && prevItem1->type == AAFI_AUDIO_CLIP ) { + + prevClip = prevItem1->data; + + if ( fadeClip->pos == (prevClip->pos + prevClip->len) ) { + + /* a previous clip is touching this fadeClip on the left */ + + if ( is_sample_accurate_edit( prevClip->essencePointerList->essenceFile->name ) ) { + + remove_sampleAccurateEditClip( aafi, audioTrack, prevItem1 ); + + if ( prevItem2 && prevItem2->type == AAFI_AUDIO_CLIP ) { + + aafiAudioClip *prevClip2 = prevItem2->data; + + if ( fadeClip->pos == (prevClip2->pos + prevClip2->len) ) { + prevClip = prevClip2; + debug( "Got a clip \"%s\" preceding fadeClip \"%s\"", + prevClip->essencePointerList->essenceFile->unique_name, + fadeClip->essencePointerList->essenceFile->unique_name ); + } else { + prevClip = NULL; } + } else { + prevClip = NULL; } - else { - nextClip = NULL; - } + } else { + debug( "Got a clip \"%s\" preceding fadeClip \"%s\"", + prevClip->essencePointerList->essenceFile->unique_name, + fadeClip->essencePointerList->essenceFile->unique_name ); } - else { - // nextClip = (aafiAudioClip*)Item->next->data; + } else { + prevClip = NULL; + } + } + + if ( nextItem1 && nextItem1->type == AAFI_AUDIO_CLIP ) { - // debug( "NEXT POS %lu", nextClip->pos ); - // debug( "CURENT POS %lu", currentpos + currentlen ); + nextClip = nextItem1->data; - if ( nextClip->pos != currentpos + currentlen ) { + if ( (fadeClip->pos + fadeClip->len) == nextClip->pos ) { + + /* a following clip is touching this fadeClip on the right */ + + if ( is_sample_accurate_edit( nextClip->essencePointerList->essenceFile->name ) ) { + + remove_sampleAccurateEditClip( aafi, audioTrack, nextItem1 ); + + if ( nextItem2 && nextItem2->type == AAFI_AUDIO_CLIP ) { + + aafiAudioClip *nextClip2 = nextItem2->data; + + if ( (fadeClip->pos + fadeClip->len) == nextClip2->pos ) { + nextClip = nextClip2; + debug( "Got a clip \"%s\" following fadeClip \"%s\"", + nextClip->essencePointerList->essenceFile->unique_name, + fadeClip->essencePointerList->essenceFile->unique_name ); + } else { + nextClip = NULL; + } + } else { nextClip = NULL; } + } else { + debug( "Got a clip \"%s\" following fadeClip \"%s\"", + nextClip->essencePointerList->essenceFile->unique_name, + fadeClip->essencePointerList->essenceFile->unique_name ); } + } else { + nextClip = NULL; } } + if ( !prevClip && !nextClip ) { + debug( "FadeClip \"%s\" is not surrounding by any touching clip", + fadeClip->essencePointerList->essenceFile->unique_name ); + return 0; + } + + + /* + * Ensures we have enough handle in surrounding clips to expand by fade length + */ + + if ( prevClip ) { + aafPosition_t essenceLength = aafi_convertUnit( prevClip->essencePointerList->essenceFile->length, prevClip->essencePointerList->essenceFile->samplerateRational, prevClip->track->edit_rate ); + + if ( (essenceLength - prevClip->essence_offset - prevClip->len) < fadeClip->len ) { + warning( "Previous clip \"%s\" has not enough handle to build a fade in place of \"%s\"", + prevClip->essencePointerList->essenceFile->unique_name, + fadeClip->essencePointerList->essenceFile->unique_name ); + return -1; + } + } + + if ( nextClip ) { + if ( nextClip->essence_offset < fadeClip->len ) { + warning( "Next clip \"%s\" has not enough handle to build a fade in place of \"%s\"", + nextClip->essencePointerList->essenceFile->unique_name, + fadeClip->essencePointerList->essenceFile->unique_name ); + return -1; + } + } + + + debug( "Replacing fadeClip \"%s\" with a %s transition of length %"PRIi64, + fadeClip->essencePointerList->essenceFile->unique_name, + (prevClip && nextClip) ? "X-Fade" : (nextClip) ? "FadeIn" : "FadeOut", + fadeClip->len ); + + + /* + * changes existing aafiTimelineItem from aafiAudioClip into aafiTransition + */ + + aafPosition_t fadeClipLength = fadeClip->len; + + fadeItem->type = AAFI_TRANS; + + aafi_freeAudioClip( fadeItem->data ); + + fadeItem->data = calloc( 1, sizeof(aafiTransition) ); + + if ( !fadeItem->data ) { + error( "Out of memory" ); + aafi_removeTimelineItem( aafi, fadeItem ); + audioTrack->clipCount--; + return 1; /* important ! */ + } + + aafiTransition *trans = fadeItem->data; + + trans->len = fadeClipLength; + trans->flags = AAFI_INTERPOL_LINEAR; trans->time_a = calloc( 2, sizeof(aafRational_t) ); trans->value_a = calloc( 2, sizeof(aafRational_t) ); - trans->time_a[0].numerator = 0; - trans->time_a[0].denominator = 0; - trans->time_a[1].numerator = 1; - trans->time_a[1].denominator = 1; + if ( !trans->time_a || !trans->value_a ) { + error( "Out of memory" ); + aafi_removeTimelineItem( aafi, fadeItem ); + audioTrack->clipCount--; + return 1; /* important ! */ + } if ( prevClip && nextClip ) { - // debug( ":: XFADE" ); + + prevClip->len += fadeClipLength; + + nextClip->pos -= fadeClipLength; + nextClip->len += fadeClipLength; + nextClip->essence_offset -= fadeClipLength; + trans->flags |= AAFI_TRANS_XFADE; + trans->cut_pt = fadeClipLength/2; trans->value_a[0].numerator = 0; trans->value_a[0].denominator = 0; @@ -237,8 +392,11 @@ static int replace_clipfade_with_fade( AAF_Iface *aafi, aafiTimelineItem *Item ) trans->value_a[1].denominator = 1; } else if ( prevClip ) { - // debug( ":: FADE OUT" ); + + prevClip->len += fadeClipLength; + trans->flags |= AAFI_TRANS_FADE_OUT; + trans->cut_pt = fadeClipLength; trans->value_a[0].numerator = 1; trans->value_a[0].denominator = 1; @@ -246,8 +404,13 @@ static int replace_clipfade_with_fade( AAF_Iface *aafi, aafiTimelineItem *Item ) trans->value_a[1].denominator = 0; } else if ( nextClip ) { - // debug( ":: FADE IN" ); + + nextClip->pos -= fadeClipLength; + nextClip->len += fadeClipLength; + nextClip->essence_offset -= fadeClipLength; + trans->flags |= AAFI_TRANS_FADE_IN; + trans->cut_pt = 0; trans->value_a[0].numerator = 0; trans->value_a[0].denominator = 0; @@ -255,51 +418,25 @@ static int replace_clipfade_with_fade( AAF_Iface *aafi, aafiTimelineItem *Item ) trans->value_a[1].denominator = 1; } + audioTrack->clipCount--; - - if ( Item->prev ) { - Item->prev->next = transItem; - transItem->prev = Item->prev; - } - else { - aafiAudioTrack *audioTrack = NULL; - - foreach_audioTrack( audioTrack, aafi ) { - - if ( audioTrack->Items == Item ) { - audioTrack->Items = transItem; - } - } - - transItem->prev = NULL; - } - - if ( Item->next ) { - Item->next->prev = transItem; - } - - - transItem->next = Item->next; - - - aafi_freeTimelineItem( &Item ); - - - return 0; + return 1; } -int protools_post_processing( AAF_Iface *aafi/*, enum protools_options flags*/ ) { +int protools_post_processing( AAF_Iface *aafi ) { aafiAudioTrack *audioTrack = NULL; - foreach_audioTrack( audioTrack, aafi ) { + AAFI_foreachAudioTrack( aafi, audioTrack ) { - aafiTimelineItem *audioItem = audioTrack->Items; + aafiTimelineItem *audioItem = audioTrack->timelineItems; while ( audioItem != NULL ) { + aafiTimelineItem *audioItemNext = audioItem->next; + if ( audioItem->type != AAFI_AUDIO_CLIP ) { audioItem = audioItem->next; continue; @@ -307,25 +444,27 @@ int protools_post_processing( AAF_Iface *aafi/*, enum protools_options flags*/ ) aafiAudioClip *audioClip = (aafiAudioClip*)audioItem->data; - wchar_t *clipName = audioClip->essencePointerList->essence->file_name; - - if ( (aafi->ctx.options.protools & PROTOOLS_REPLACE_CLIP_FADES) && is_rendered_fade( clipName ) ) { - - replace_clipfade_with_fade( aafi, audioItem ); + char *clipName = audioClip->essencePointerList->essenceFile->name; - audioItem = audioTrack->Items; - continue; + if ( (aafi->ctx.options.protools & AAFI_PROTOOLS_OPT_REPLACE_CLIP_FADES) && + is_rendered_fade( clipName ) ) + { + if ( replace_clipFade( aafi, audioTrack, audioItem ) > 0 ) { + audioItem = audioTrack->timelineItems; + continue; + } } else - if ( (aafi->ctx.options.protools & PROTOOLS_REMOVE_SAMPLE_ACCURATE_EDIT) && is_sample_accurate_edit( clipName ) ) { - - aafi_removeTimelineItem( aafi, audioItem ); - - audioItem = audioTrack->Items; - continue; + if ( (aafi->ctx.options.protools & AAFI_PROTOOLS_OPT_REMOVE_SAMPLE_ACCURATE_EDIT) && + is_sample_accurate_edit( clipName ) ) + { + if ( remove_sampleAccurateEditClip( aafi, audioTrack, audioItem ) ) { + audioItem = audioTrack->timelineItems; + continue; + } } - audioItem = audioItem->next; + audioItem = audioItemNext; } } diff --git a/src/AAFIface/RIFFParser.c b/src/AAFIface/RIFFParser.c index b402037..1d628d5 100644 --- a/src/AAFIface/RIFFParser.c +++ b/src/AAFIface/RIFFParser.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Adrien Gesta-Fline + * Copyright (C) 2023-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -22,19 +22,18 @@ #include #include #include -#include #include "RIFFParser.h" #define debug( ... ) \ - _dbg( dbg, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) + AAF_LOG( log, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) #define warning( ... ) \ - _dbg( dbg, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) + AAF_LOG( log, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) #define error( ... ) \ - _dbg( dbg, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) + AAF_LOG( log, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) #define BE2LE32( val ) \ @@ -47,10 +46,10 @@ static uint32_t beExtended2leUint32( const unsigned char numx[10] ); -int riff_writeWavFileHeader( FILE *fp, struct wavFmtChunk *wavFmt, struct wavBextChunk *wavBext, uint32_t audioDataSize, struct dbg *dbg ) { +int laaf_riff_writeWavFileHeader( FILE *fp, struct wavFmtChunk *wavFmt, struct wavBextChunk *wavBext, uint32_t audioDataSize, struct aafLog *log ) { - (void)dbg; - uint32_t filesize = (4 /* WAVE */) + sizeof(struct wavFmtChunk) + ((wavBext) ? sizeof(struct wavBextChunk) : 0) + (8 /*data chunk header*/) + audioDataSize; + (void)log; + size_t filesize = (4 /* WAVE */) + sizeof(struct wavFmtChunk) + ((wavBext) ? sizeof(struct wavBextChunk) : 0) + (8 /*data chunk header*/) + audioDataSize; size_t writtenBytes = fwrite( "RIFF", sizeof(unsigned char), 4, fp ); @@ -77,7 +76,7 @@ int riff_writeWavFileHeader( FILE *fp, struct wavFmtChunk *wavFmt, struct wavBex wavFmt->cksz = sizeof(struct wavFmtChunk) - sizeof(struct riffChunk); wavFmt->format_tag = 1; /* PCM */ wavFmt->avg_bytes_per_sec = wavFmt->samples_per_sec * wavFmt->channels * wavFmt->bits_per_sample/8; - wavFmt->block_align = wavFmt->channels * wavFmt->bits_per_sample/8; + wavFmt->block_align = wavFmt->channels * (wavFmt->bits_per_sample>>3); writtenBytes = fwrite( (unsigned char*)wavFmt, sizeof(unsigned char), sizeof(struct wavFmtChunk), fp ); @@ -117,7 +116,7 @@ int riff_writeWavFileHeader( FILE *fp, struct wavFmtChunk *wavFmt, struct wavBex -int riff_parseAudioFile( struct RIFFAudioFile *RIFFAudioFile, enum RIFF_PARSER_FLAGS flags, size_t (*readerCallback)(unsigned char *, size_t, size_t, void*, void*, void*), void *user1, void *user2, void *user3, struct dbg *dbg ) { +int laaf_riff_parseAudioFile( struct RIFFAudioFile *RIFFAudioFile, enum RIFF_PARSER_FLAGS flags, size_t (*readerCallback)(unsigned char *, size_t, size_t, void*, void*, void*), void *user1, void *user2, void *user3, struct aafLog *log ) { struct riffChunk chunk; struct riffHeaderChunk riff; @@ -127,7 +126,9 @@ int riff_parseAudioFile( struct RIFFAudioFile *RIFFAudioFile, enum RIFF_PARSER_F size_t bytesRead = readerCallback( (unsigned char*)&riff, 0, sizeof(riff), user1, user2, user3 ); - if ( bytesRead < sizeof(riff) ) { + if ( bytesRead == RIFF_READER_ERROR || + bytesRead < sizeof(riff) ) + { error( "Could not read file header" ); return -1; } @@ -167,13 +168,16 @@ int riff_parseAudioFile( struct RIFFAudioFile *RIFFAudioFile, enum RIFF_PARSER_F size_t filesize = riff.cksz + sizeof(chunk); + size_t pos_sz = 0; size_t pos = sizeof(struct riffHeaderChunk); while ( pos < filesize ) { bytesRead = readerCallback( (unsigned char*)&chunk, pos, sizeof(chunk), user1, user2, user3 ); - if ( bytesRead < sizeof(chunk) ) { + if ( bytesRead == RIFF_READER_ERROR || + bytesRead < sizeof(chunk) ) + { error( "Could not read chunk \"%.4s\" @ %"PRIu64" (%"PRIu64" bytes returned)", chunk.ckid, pos, bytesRead ); break; } @@ -196,7 +200,9 @@ int riff_parseAudioFile( struct RIFFAudioFile *RIFFAudioFile, enum RIFF_PARSER_F bytesRead = readerCallback( (unsigned char*)&wavFmtChunk, pos, sizeof(wavFmtChunk), user1, user2, user3 ); - if ( bytesRead < sizeof(wavFmtChunk) ) { + if ( bytesRead == RIFF_READER_ERROR || + bytesRead < sizeof(riff) ) + { error( "Could not read chunk \"%.4s\" content @ %"PRIu64" (%"PRIu64" bytes returned)", chunk.ckid, pos, bytesRead ); break; } @@ -219,6 +225,8 @@ int riff_parseAudioFile( struct RIFFAudioFile *RIFFAudioFile, enum RIFF_PARSER_F RIFFAudioFile->sampleCount = chunk.cksz / RIFFAudioFile->channels / (RIFFAudioFile->sampleSize / 8); } + RIFFAudioFile->pcm_audio_start_offset = (pos + sizeof(struct riffChunk)); + if ( flags & RIFF_PARSE_AAF_SUMMARY ) { return 0; } @@ -235,7 +243,9 @@ int riff_parseAudioFile( struct RIFFAudioFile *RIFFAudioFile, enum RIFF_PARSER_F bytesRead = readerCallback( (unsigned char*)&aiffCOMMChunk, pos, sizeof(aiffCOMMChunk), user1, user2, user3 ); - if ( bytesRead < sizeof(aiffCOMMChunk) ) { + if ( bytesRead == RIFF_READER_ERROR || + bytesRead < sizeof(riff) ) + { error( "Could not read chunk \"%.4s\" content @ %"PRIu64" (%"PRIu64" bytes returned)", chunk.ckid, pos, bytesRead ); break; } @@ -267,6 +277,7 @@ int riff_parseAudioFile( struct RIFFAudioFile *RIFFAudioFile, enum RIFF_PARSER_F } RIFFAudioFile->sampleCount = sampleCount; + RIFFAudioFile->pcm_audio_start_offset = pos + sizeof(struct aiffSSNDChunk); if ( flags & RIFF_PARSE_AAF_SUMMARY ) { return 0; @@ -274,7 +285,14 @@ int riff_parseAudioFile( struct RIFFAudioFile *RIFFAudioFile, enum RIFF_PARSER_F } } - pos += chunk.cksz+sizeof(chunk); + pos_sz = chunk.cksz+sizeof(chunk); + + if ( pos_sz >= SIZE_MAX ) { + error( "Parser position is bigger than RIFF_SIZE limits" ); + break; + } + + pos += pos_sz; } return 0; @@ -283,6 +301,7 @@ int riff_parseAudioFile( struct RIFFAudioFile *RIFFAudioFile, enum RIFF_PARSER_F static uint32_t beExtended2leUint32( const unsigned char numx[10] ) { + /* * https://stackoverflow.com/a/18854415/16400184 */ @@ -319,7 +338,7 @@ static uint32_t beExtended2leUint32( const unsigned char numx[10] ) { else { /* Otherwise it's denormal. It cannot be represented as double. Translate as singed zero. */ memcpy( &result, d, 8 ); - return result; + return (uint32_t)result; } } else { @@ -328,7 +347,7 @@ static uint32_t beExtended2leUint32( const unsigned char numx[10] ) { if ( exponent <= -52 ) { /*< Too small to represent. Translate as (signed) zero. */ memcpy( &result, d, 8 ); - return result; + return (uint32_t)result; } else if ( exponent < 0 ) { /* Denormal, exponent bits are already zero here. */ @@ -338,12 +357,12 @@ static uint32_t beExtended2leUint32( const unsigned char numx[10] ) { d[6] = 0xF0; memset( d, 0x00, 6 ); memcpy( &result, d, 8 ); - return result; + return (uint32_t)result; } else { /* Representable number */ d[7] |= (exponent & 0x7F0) >> 4; - d[6] |= (exponent & 0xF) << 4; + d[6] |= (unsigned char)((exponent & 0xF) << 4); } } diff --git a/src/AAFIface/RIFFParser.h b/src/AAFIface/RIFFParser.h index 6698375..14ad0a8 100644 --- a/src/AAFIface/RIFFParser.h +++ b/src/AAFIface/RIFFParser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Adrien Gesta-Fline + * Copyright (C) 2023-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -21,8 +21,17 @@ #ifndef __RIFFParser__ #define __RIFFParser__ -#include +#include +#if defined(__linux__) + #include + #include +#elif defined(__APPLE__) + #include +#elif defined(_WIN32) + #include // MAX_PATH + #include +#endif #ifdef __GNUC__ @@ -34,6 +43,10 @@ #endif + +#define RIFF_READER_ERROR SIZE_MAX + + enum RIFF_PARSER_FLAGS { RIFF_PARSE_ONLY_HEADER = (1 << 0), RIFF_PARSE_AAF_SUMMARY = (1 << 1), @@ -47,6 +60,7 @@ struct RIFFAudioFile { uint16_t sampleSize; uint16_t channels; uint64_t sampleCount; /* total samples for 1 channel (no matter channel count). (sampleCount / sampleRate) = duration in seconds */ + size_t pcm_audio_start_offset; }; @@ -71,7 +85,7 @@ PACK(struct riffChunk { PACK(struct wavFmtChunk { - char ckid[4]; //'fmt ' + char ckid[4]; /* 'fmt ' */ uint32_t cksz; uint16_t format_tag; @@ -85,7 +99,7 @@ PACK(struct wavFmtChunk { PACK(struct wavBextChunk { - char ckid[4]; //'bext' + char ckid[4]; /* 'bext' */ uint32_t cksz; char description[256]; @@ -129,7 +143,7 @@ PACK(struct wavBextChunk { PACK(struct aiffCOMMChunk { - char ckid[4]; //'COMM' + char ckid[4]; /* 'COMM' */ uint32_t cksz; uint16_t numChannels; @@ -139,10 +153,19 @@ PACK(struct aiffCOMMChunk { }); +PACK(struct aiffSSNDChunk { + char ckid[4]; /* 'SSND' */ + uint32_t cksz; + + uint32_t offset; + uint32_t blockSize; +}); + + -int riff_parseAudioFile( struct RIFFAudioFile *RIFFAudioFile, enum RIFF_PARSER_FLAGS flags, size_t (*readerCallback)(unsigned char *, size_t, size_t, void*, void*, void*), void *user1, void *user2, void *user3, struct dbg *dbg ); +int laaf_riff_parseAudioFile( struct RIFFAudioFile *RIFFAudioFile, enum RIFF_PARSER_FLAGS flags, size_t (*readerCallback)(unsigned char *, size_t, size_t, void*, void*, void*), void *user1, void *user2, void *user3, struct aafLog *log ); -int riff_writeWavFileHeader( FILE *fp, struct wavFmtChunk *wavFmt, struct wavBextChunk *wavBext, uint32_t audioDataSize, struct dbg *dbg ); +int laaf_riff_writeWavFileHeader( FILE *fp, struct wavFmtChunk *wavFmt, struct wavBextChunk *wavBext, uint32_t audioDataSize, struct aafLog *log ); #endif // ! __RIFFParser__ diff --git a/src/AAFIface/Resolve.c b/src/AAFIface/Resolve.c index 6290c38..54967cc 100644 --- a/src/AAFIface/Resolve.c +++ b/src/AAFIface/Resolve.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Adrien Gesta-Fline + * Copyright (C) 2023-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -27,17 +27,17 @@ #include #include -#include +#include #define debug( ... ) \ - _dbg( aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) #define warning( ... ) \ - _dbg( aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) #define error( ... ) \ - _dbg( aafi->dbg, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) + AAF_LOG( aafi->log, aafi, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) @@ -45,11 +45,11 @@ int resolve_AAF( struct AAF_Iface *aafi ) { int probe = 0; - if ( aafi->aafd->Identification.CompanyName && wcsncmp( aafi->aafd->Identification.CompanyName, L"Blackmagic Design", wcslen( L"Blackmagic Design" ) ) == 0 ) { + if ( aafi->aafd->Identification.CompanyName && strncmp( aafi->aafd->Identification.CompanyName, "Blackmagic Design", strlen( "Blackmagic Design" ) ) == 0 ) { probe++; } - if ( aafi->aafd->Identification.ProductName && wcsncmp( aafi->aafd->Identification.ProductName, L"DaVinci Resolve", wcslen( L"DaVinci Resolve" ) ) == 0 ) { + if ( aafi->aafd->Identification.ProductName && strncmp( aafi->aafd->Identification.ProductName, "DaVinci Resolve", strlen( "DaVinci Resolve" ) ) == 0 ) { probe++; } @@ -59,181 +59,3 @@ int resolve_AAF( struct AAF_Iface *aafi ) return 0; } - - - -int resolve_parse_aafObject_Selector( struct AAF_Iface *aafi, aafObject *Selector, td *__ptd ) -{ - /* - * Resolve 18.5 - * - * The Selector Object was only seen used to describe a disabled clip : - * - Selected property Object is an empty Filler - * - Alternate keeps track of the original clip. - * -03411││ ├──◻ AAFClassID_Selector -01926││ Selected --> │ └──◻ AAFClassID_Filler -02359││ Alternate -> │ └──◻ AAFClassID_OperationGroup (OpIdent: AAFOperationDef_MonoAudioGain) -03822││ │ ├──◻ AAFClassID_VaryingValue -02877││ │ └──◻ AAFClassID_SourceClip -02882││ │ └──◻ AAFClassID_MasterMob (UsageCode: n/a) : speech-sample.mp3 - disabled -04460││ │ └──◻ AAFClassID_TimelineMobSlot -03089││ │ └──◻ AAFClassID_SourceClip -04167││ │ └──◻ AAFClassID_SourceMob (UsageCode: n/a) : speech-sample.mp3 - disabled -01249││ │ └──◻ AAFClassID_PCMDescriptor -01455││ │ └──◻ AAFClassID_NetworkLocator : file:///C:/Users/user/Desktop/libAAF/test/res/speech-sample.mp3 - */ - - struct trace_dump __td; - __td_set(__td, __ptd, 0); - - - - aafObject *Selected = aaf_get_propertyValue( Selector, PID_Selector_Selected, &AAFTypeID_SegmentStrongReference ); - - if ( Selected == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, Selector, &__td, "Missing PID_Selector_Selected" ); - return -1; - } - - aafObject *Alternates = aaf_get_propertyValue( Selector, PID_Selector_Alternates, &AAFTypeID_SegmentStrongReferenceVector ); - - if ( Alternates == NULL ) { /* opt */ - DUMP_OBJ_WARNING( aafi, Selector, &__td, "Missing PID_Selector_Alternates" ); - return -1; - } - - - void *ComponentAttributeList = aaf_get_propertyValue( Selector, aaf_get_PropertyIDByName( aafi->aafd, L"ComponentAttributeList" ), &AAFUID_NULL ); - - if ( ComponentAttributeList == NULL ) { - DUMP_OBJ_ERROR( aafi, Selector, &__td, "Missing AAFClassID_Selector::ComponentAttributeList" ); - return -1; - } - - - DUMP_OBJ( aafi, Selector, &__td ); - - - // aaf_dump_ObjectProperties( aafi->aafd, Selector ); - // aaf_dump_ObjectProperties( aafi->aafd, ComponentAttributeList ); - - - int ismuted = 0; - aafObject *ComponentAttribute = NULL; - - aaf_foreach_ObjectInSet( &ComponentAttribute, ComponentAttributeList, NULL ) { - /* TODO implement retrieve_TaggedValue() */ - - wchar_t *name = aaf_get_propertyValue( ComponentAttribute, PID_TaggedValue_Name, &AAFTypeID_String ); - - if ( name == NULL ) { /* req */ - DUMP_OBJ_ERROR( aafi, ComponentAttribute, &__td, "Missing PID_TaggedValue_Name" ); - continue; - } - - - aafIndirect_t *Indirect = aaf_get_propertyValue( ComponentAttribute, PID_TaggedValue_Value, &AAFTypeID_Indirect ); - - if ( Indirect == NULL ) { - DUMP_OBJ_ERROR( aafi, ComponentAttribute, &__td, "Missing PID_TaggedValue_Value" ); - free( name ); - continue; - } - - int32_t *value = aaf_get_indirectValue( aafi->aafd, Indirect, &AAFTypeID_Int32 ); - - if ( value == NULL ) { - DUMP_OBJ_ERROR( aafi, ComponentAttribute, &__td, "Could not retrieve Indirect value for PID_TaggedValue_Value" ); - free( name ); - continue; - } - - - // debug( "Tagged | Name: %ls Value : %u", name, *value ); - - if ( aafi->ctx.options.resolve & RESOLVE_INCLUDE_DISABLED_CLIPS ) { - if ( wcsncmp( name, L"_DISABLE_CLIP_FLAG", wcslen( L"_DISABLE_CLIP_FLAG" ) ) == 0 && *value == 1 ) { - - ismuted = 1; - aafi->ctx.current_clip_is_muted = 1; - - aafObject *Alternate = NULL; - - int i = 0; - aaf_foreach_ObjectInSet( &Alternate, Alternates, NULL ) { - if ( i == 0 ) { /* there should be only one Segment in set, but still. Let's be carefull */ - aafi_parse_Segment( aafi, Alternate, &__td ); - } - else { - DUMP_OBJ_ERROR( aafi, Alternate, &__td, "Multiple Alternates in Davinci Resolve selector" ); - } - i++; - } - } - } - - free( name ); - } - - /* aafi->ctx.current_clip_is_muted was already reset at this point */ - if ( ismuted == 0 ) { - return aafi_parse_Segment( aafi, Selected, &__td ); - } - - return 0; -} - - - -int resolve_parse_aafObject_DescriptiveMarker( struct AAF_Iface *aafi, aafObject *DescriptiveMarker, td *__ptd ) -{ - /* - * Resolve 18.5 - */ - - struct trace_dump __td; - __td_set(__td, __ptd, 1); - - - aafPosition_t *start = aaf_get_propertyValue( DescriptiveMarker, PID_Event_Position, &AAFTypeID_PositionType ); - - if ( start == NULL ) { /* req (TODO: conditional) */ - DUMP_OBJ_ERROR( aafi, DescriptiveMarker, &__td, "Missing PID_Event_Position" ); - return -1; - } - - - aafPosition_t *length = aaf_get_propertyValue( DescriptiveMarker, PID_Component_Length, &AAFTypeID_PositionType ); - - wchar_t *comment = aaf_get_propertyValue( DescriptiveMarker, PID_Event_Comment, &AAFTypeID_String ); - - wchar_t *name = aaf_get_propertyValue( DescriptiveMarker, aaf_get_PropertyIDByName( aafi->aafd, L"CommentMarkerUser" ), &AAFTypeID_String ); - - uint16_t *RGBColor = NULL; - - aafProperty *RGBColorProp = aaf_get_property( DescriptiveMarker, aaf_get_PropertyIDByName( aafi->aafd, L"CommentMarkerColor" ) ); - - if ( RGBColorProp ) { - - if ( RGBColorProp->len != sizeof(uint16_t)*3 ) { - error( "CommentMarkerColor has wrong size of %u", RGBColorProp->len ); - } - else { - - RGBColor = RGBColorProp->val; - - /* big endian to little endian */ - - RGBColor[0] = (RGBColor[0]>>8) | (RGBColor[0]<<8); - RGBColor[1] = (RGBColor[1]>>8) | (RGBColor[1]<<8); - RGBColor[2] = (RGBColor[2]>>8) | (RGBColor[2]<<8); - } - } - - aafi_newMarker( aafi, aafi->ctx.current_markers_edit_rate, *start, ((length) ? *length : 0), name, comment, &RGBColor ); - - DUMP_OBJ( aafi, DescriptiveMarker, &__td ); - - return 0; -} diff --git a/src/AAFIface/URIParser.c b/src/AAFIface/URIParser.c index d6f8a87..09ce6e9 100644 --- a/src/AAFIface/URIParser.c +++ b/src/AAFIface/URIParser.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Adrien Gesta-Fline + * Copyright (C) 2023-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -24,24 +24,26 @@ #include #include #include +#include #ifdef _MSC_VER #include typedef SSIZE_T ssize_t; #endif +#include #include "URIParser.h" #define debug( ... ) \ - _dbg( dbg, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) + AAF_LOG( log, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_DEBUG, __VA_ARGS__ ) #define warning( ... ) \ - _dbg( dbg, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) + AAF_LOG( log, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_WARNING, __VA_ARGS__ ) #define error( ... ) \ - _dbg( dbg, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) + AAF_LOG( log, NULL, DEBUG_SRC_ID_AAF_IFACE, VERB_ERROR, __VA_ARGS__ ) @@ -94,42 +96,36 @@ ( uri->scheme_t != URI_SCHEME_T_FILE && \ !(uri->opts & URI_OPT_IGNORE_FRAGMENT) ) -#define URI_SET_STR( str, start, end ) \ - \ - str = malloc( sizeof(char) * ((end - start) + 1) ); \ - \ - if ( NULL == str ) { \ - error( "URI allocation failed" ); \ - goto err; \ - } \ - \ - snprintf( str, (end - start)+1, "%s", start ); \ +#define URI_SET_STR( str, start, end ) \ + \ + str = malloc( sizeof(char) * (uint32_t)((end - start) + 1) ); \ + \ + if ( !str ) { \ + error( "Out of memory" ); \ + goto err; \ + } \ + \ + snprintf( str, (uint32_t)(end - start)+1, "%s", start ); \ -static int _uri_parse_scheme( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ); -static int _uri_parse_authority( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ); -static int _uri_parse_userinfo( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ); -static int _uri_parse_hostname( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ); -static int _uri_parse_path( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ); -static int _uri_parse_query( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ); -static int _uri_parse_fragment( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ); +static char * uriDecodeString( char *src, char *dst ); +static int uriIsIPv4( const char *s, size_t size, char **err ); +static int uriIsIPv6( const char *s, size_t size, char **err ); -static void _uri_scheme2schemeType( struct uri *uri ); -static int _laaf_util_snprintf_realloc( char **str, size_t *size, size_t offset, const char *format, ... ); - -#ifdef BUILD_URI_TEST // gcc -g -W -Wall ./URIParser.c -D BUILD_URI_TEST - static int _uri_cmp( const struct uri *a, const struct uri *b ); - static void _uri_dump_diff( struct uri *a, struct uri *b, int totalDifferencies ); - static int _uri_test( const char *uristr, enum uri_option optflags, struct uri expectedRes, int line ); -#endif // BUILD_URI_TEST +static int _uri_parse_scheme( struct uri *uri, const char **pos, const char *end, struct aafLog *log ); +static int _uri_parse_authority( struct uri *uri, const char **pos, const char *end, struct aafLog *log ); +static int _uri_parse_userinfo( struct uri *uri, const char **pos, const char *end, struct aafLog *log ); +static int _uri_parse_hostname( struct uri *uri, const char **pos, const char *end, struct aafLog *log ); +static int _uri_parse_path( struct uri *uri, const char **pos, const char *end, struct aafLog *log ); +static int _uri_parse_query( struct uri *uri, const char **pos, const char *end, struct aafLog *log ); +static int _uri_parse_fragment( struct uri *uri, const char **pos, const char *end, struct aafLog *log ); +static void _uri_scheme2schemeType( struct uri *uri ); -char * uriDecodeString( char *src, char *dst ) { - int inpos = 0; - int outpos = 0; +static char * uriDecodeString( char *src, char *dst ) { if ( src == NULL ) { return NULL; @@ -139,51 +135,43 @@ char * uriDecodeString( char *src, char *dst ) { dst = src; } - while ( src[inpos] ) { + char *end = src + strlen(src); + + while ( *src ) { - if ( src[inpos] == '%' && IS_HEX(src[inpos+1]) && IS_HEX(src[inpos+2]) ) { + if ( *src == '%' && src+2 < end && IS_HEX(*(src+1)) && IS_HEX(*(src+2)) ) { - int c = 0; + char d1 = *(src+1); + char d2 = *(src+2); - char hex1 = src[inpos+1]; + int digit = 0; - if ((hex1 >= '0') && (hex1 <= '9')) - c = (hex1 - '0'); - else if ((hex1 >= 'a') && (hex1 <= 'f')) - c = (hex1 - 'a') + 10; - else if ((hex1 >= 'A') && (hex1 <= 'F')) - c = (hex1 - 'A') + 10; + digit = (d1 >= 'A' ? ((d1 & 0xdf) - 'A') + 10 : (d1 - '0')); + digit <<= 4; + digit += (d2 >= 'A' ? ((d2 & 0xdf) - 'A') + 10 : (d2 - '0')); - char hex2 = src[inpos+2]; + assert( digit > CHAR_MIN && digit < UCHAR_MAX ); - if ((hex2 >= '0') && (hex2 <= '9')) - c = c * 16 + (hex2 - '0'); - else if ((hex2 >= 'a') && (hex2 <= 'f')) - c = c * 16 + (hex2 - 'a') + 10; - else if ((hex2 >= 'A') && (hex2 <= 'F')) - c = c * 16 + (hex2 - 'A') + 10; + *dst = (char)digit; - dst[outpos] = (char)c; - inpos+=3; + src += 3; + dst++; } else { - dst[outpos] = src[inpos]; - inpos++; + *dst = *src; + src++; + dst++; } - - outpos++; } - if ( inpos > outpos ) { - dst[outpos] = 0x00; - } + *dst = 0x00; return dst; } -static int _uri_parse_scheme( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ) { +static int _uri_parse_scheme( struct uri *uri, const char **pos, const char *end, struct aafLog *log ) { const char *p = *pos; @@ -217,7 +205,14 @@ static int _uri_parse_scheme( struct uri *uri, const char **pos, const char *end char *pp = uri->scheme; while ( *pp ) { - *pp = tolower( *pp ); pp++; + + int charint = tolower( *pp ); + + assert( charint > CHAR_MIN && charint < CHAR_MAX ); + + *pp = (char)charint; + + pp++; } _uri_scheme2schemeType( uri ); @@ -232,7 +227,7 @@ static int _uri_parse_scheme( struct uri *uri, const char **pos, const char *end -static int _uri_parse_authority( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ) { +static int _uri_parse_authority( struct uri *uri, const char **pos, const char *end, struct aafLog *log ) { /* * RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax @@ -302,7 +297,7 @@ static int _uri_parse_authority( struct uri *uri, const char **pos, const char * -static int _uri_parse_userinfo( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ) { +static int _uri_parse_userinfo( struct uri *uri, const char **pos, const char *end, struct aafLog *log ) { int hasUserinfo = 0; int userinfoIllegalCharacters = 0; @@ -383,7 +378,7 @@ static int _uri_parse_userinfo( struct uri *uri, const char **pos, const char *e -static int _uri_parse_hostname( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ) { +static int _uri_parse_hostname( struct uri *uri, const char **pos, const char *end, struct aafLog *log ) { const char *p = *pos; @@ -438,7 +433,7 @@ static int _uri_parse_hostname( struct uri *uri, const char **pos, const char *e p++; } - // debug( " >>> %.*s", (int)(p-*pos), p ); + // debug( L" >>> %.*s", (int)(p-*pos), p ); URI_SET_STR( uri->host, *pos, p ); } @@ -448,7 +443,7 @@ static int _uri_parse_hostname( struct uri *uri, const char **pos, const char *e if ( !(uri->flags & URI_T_HOST_IPV6) && uri->host != NULL && *uri->host != 0x00 ) { if ( uriIsIPv4( uri->host, strlen(uri->host), NULL ) ) { - uri->flags &= ~URI_T_HOST_MASK; + uri->flags &= ~(unsigned)URI_T_HOST_MASK; uri->flags |= URI_T_HOST_IPV4; if ( strcmp( uri->host, "127.0.0.1" ) == 0 ) { uri->flags |= URI_T_LOCALHOST; @@ -503,7 +498,7 @@ static int _uri_parse_hostname( struct uri *uri, const char **pos, const char *e -static int _uri_parse_path( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ) { +static int _uri_parse_path( struct uri *uri, const char **pos, const char *end, struct aafLog *log ) { int winDrive = 0; @@ -532,7 +527,7 @@ static int _uri_parse_path( struct uri *uri, const char **pos, const char *end, p++; } - // debug( " >>> (%i) %.*s", (int)(p-*pos), (int)(p-*pos), p ); + // debug( L" >>> (%i) %.*s", (int)(p-*pos), (int)(p-*pos), p ); URI_SET_STR( uri->path, *pos, p ); @@ -560,7 +555,7 @@ static int _uri_parse_path( struct uri *uri, const char **pos, const char *end, -static int _uri_parse_query( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ) { +static int _uri_parse_query( struct uri *uri, const char **pos, const char *end, struct aafLog *log ) { const char *p = *pos; @@ -589,7 +584,7 @@ static int _uri_parse_query( struct uri *uri, const char **pos, const char *end, -static int _uri_parse_fragment( struct uri *uri, const char **pos, const char *end, struct dbg *dbg ) { +static int _uri_parse_fragment( struct uri *uri, const char **pos, const char *end, struct aafLog *log ) { /* * https://datatracker.ietf.org/doc/html/draft-yevstifeyev-ftp-uri-scheme#section-3.2.4.2 @@ -632,7 +627,7 @@ static int _uri_parse_fragment( struct uri *uri, const char **pos, const char *e -struct uri * uriParse( const char *uristr, enum uri_option optflags, struct dbg *dbg ) { +struct uri * laaf_uri_parse( const char *uristr, enum uri_option optflags, struct aafLog *log ) { if ( uristr == NULL ) { return NULL; @@ -640,7 +635,8 @@ struct uri * uriParse( const char *uristr, enum uri_option optflags, struct dbg struct uri *uri = calloc( 1, sizeof(struct uri) ); - if ( uri == NULL ) { + if ( !uri ) { + error( "Out of memory" ); return NULL; } @@ -658,28 +654,28 @@ struct uri * uriParse( const char *uristr, enum uri_option optflags, struct dbg const char *end = pos + urilen; - _uri_parse_scheme( uri, &pos, end, dbg ); + _uri_parse_scheme( uri, &pos, end, log ); - if ( _uri_parse_authority( uri, &pos, end, dbg ) ) { - _uri_parse_userinfo( uri, &pos, end, dbg ); - _uri_parse_hostname( uri, &pos, end, dbg ); + if ( _uri_parse_authority( uri, &pos, end, log ) ) { + _uri_parse_userinfo( uri, &pos, end, log ); + _uri_parse_hostname( uri, &pos, end, log ); } - _uri_parse_path( uri, &pos, end, dbg ); + _uri_parse_path( uri, &pos, end, log ); if ( SCHEME_ALLOW_QUERY( uri ) ) { - _uri_parse_query( uri, &pos, end, dbg ); + _uri_parse_query( uri, &pos, end, log ); } if ( SCHEME_ALLOW_FRAGMENT( uri ) ) { - _uri_parse_fragment( uri, &pos, end, dbg ); + _uri_parse_fragment( uri, &pos, end, log ); } goto end; err: - uriFree( uri ); + laaf_uri_free( uri ); uri = NULL; end: @@ -689,45 +685,28 @@ struct uri * uriParse( const char *uristr, enum uri_option optflags, struct dbg -void uriFree( struct uri *uri ) +void laaf_uri_free( struct uri *uri ) { - if ( uri == NULL ) { + if ( !uri ) { return; } - if ( NULL != uri->scheme ) { - free(uri->scheme); - } - if ( NULL != uri->userinfo ) { - free(uri->userinfo); - } - if ( NULL != uri->authority ) { - free(uri->authority); - } - if ( NULL != uri->user ) { - free(uri->user); - } - if ( NULL != uri->pass ) { - free(uri->pass); - } - if ( NULL != uri->host ) { - free(uri->host); - } - if ( NULL != uri->path ) { - free(uri->path); - } - if ( NULL != uri->query ) { - free(uri->query); - } - if ( NULL != uri->fragment ) { - free(uri->fragment); - } + + free(uri->scheme); + free(uri->userinfo); + free(uri->authority); + free(uri->user); + free(uri->pass); + free(uri->host); + free(uri->path); + free(uri->query); + free(uri->fragment); free(uri); } -int uriIsIPv4( const char *s, int size, char **err ) { +static int uriIsIPv4( const char *s, size_t size, char **err ) { int octets = 0; const char *currentOctetStart = s; @@ -735,7 +714,7 @@ int uriIsIPv4( const char *s, int size, char **err ) { char prev = 0; - for ( int i = 0; i <= size; i++ ) { + for ( size_t i = 0; i <= size; i++ ) { if ( prev == 0 ) { @@ -747,7 +726,7 @@ int uriIsIPv4( const char *s, int size, char **err ) { if ( *(s+i) == '.' ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : can't start with a single '.'" ); + laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : can't start with a single '.'" ); } return 0; } @@ -763,7 +742,7 @@ int uriIsIPv4( const char *s, int size, char **err ) { if ( *(s+i) == '.' ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : can't have successive '.'" ); + laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : can't have successive '.'" ); } return 0; } @@ -781,14 +760,14 @@ int uriIsIPv4( const char *s, int size, char **err ) { int octet = atoi(currentOctetStart); if ( octet > 255 ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : octet %i is too high : %.*s", (octets), (int)((s+i) - currentOctetStart), currentOctetStart ); + laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : octet %i is too high : %.*s", (octets), (int)((s+i) - currentOctetStart), currentOctetStart ); } return 0; } if ( i+1 == size ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : can't end with a single '.'" ); + laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : can't end with a single '.'" ); } return 0; } @@ -804,7 +783,7 @@ int uriIsIPv4( const char *s, int size, char **err ) { } if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : illegal char '%c' (0x%02x)", *(s+i), *(s+i) ); + laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : illegal char '%c' (0x%02x)", *(s+i), *(s+i) ); } return 0; } @@ -812,13 +791,13 @@ int uriIsIPv4( const char *s, int size, char **err ) { if ( octets > 4 ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : too many octets" ); + laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : too many octets" ); } return 0; } if ( octets < 4 ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : not enough octets" ); + laaf_util_snprintf_realloc( err, NULL, 0, "IPV4 parser error : not enough octets" ); } return 0; } @@ -829,7 +808,7 @@ int uriIsIPv4( const char *s, int size, char **err ) { -int uriIsIPv6( const char *s, int size, char **err ) { +static int uriIsIPv6( const char *s, size_t size, char **err ) { int segmentCount = 0; int emptySegmentCount = 0; @@ -843,7 +822,7 @@ int uriIsIPv6( const char *s, int size, char **err ) { char prev = 0; - for ( int i = 0; i <= size; i++ ) { + for ( size_t i = 0; i <= size; i++ ) { if ( prev == 0 ) { @@ -873,7 +852,7 @@ int uriIsIPv6( const char *s, int size, char **err ) { if ( *(s+i) == ':' ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "can't start with a single ':'" ); + laaf_util_snprintf_realloc( err, NULL, 0, "can't start with a single ':'" ); } return 0; } @@ -901,11 +880,11 @@ int uriIsIPv6( const char *s, int size, char **err ) { int octet = atoi(curSegmentStart); if ( octet > 255 ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "ipv4 portion octet %i is too high : %.*s", (ipv4portion), curSegmentLength, curSegmentStart ); + laaf_util_snprintf_realloc( err, NULL, 0, "ipv4 portion octet %i is too high : %.*s", (ipv4portion), curSegmentLength, curSegmentStart ); } return 0; } - // debug( "%i", octet ); + // debug( L"%i", octet ); prev = 'p'; ipv4portion++; continue; @@ -914,7 +893,7 @@ int uriIsIPv6( const char *s, int size, char **err ) { if ( i == size || *(s+i) == ':' ) { if ( curSegmentLength > 4 ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "segment %i is too long : %.*s", (segmentCount-1), curSegmentLength, curSegmentStart ); + laaf_util_snprintf_realloc( err, NULL, 0, "segment %i is too long : %.*s", (segmentCount-1), curSegmentLength, curSegmentStart ); } return 0; } @@ -930,7 +909,7 @@ int uriIsIPv6( const char *s, int size, char **err ) { else if ( i+1 == size ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "can't end with a single ':'" ); + laaf_util_snprintf_realloc( err, NULL, 0, "can't end with a single ':'" ); } return 0; } @@ -963,7 +942,7 @@ int uriIsIPv6( const char *s, int size, char **err ) { if ( *(s+i) == ':' ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "can't have more than two successive ':'" ); + laaf_util_snprintf_realloc( err, NULL, 0, "can't have more than two successive ':'" ); } return 0; } @@ -980,7 +959,7 @@ int uriIsIPv6( const char *s, int size, char **err ) { if ( *(s+i) == '.' ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "can't have successive '.'" ); + laaf_util_snprintf_realloc( err, NULL, 0, "can't have successive '.'" ); } return 0; } @@ -989,7 +968,7 @@ int uriIsIPv6( const char *s, int size, char **err ) { if ( prev == 'd' ) { - if ( IS_DIGIT(*(s+i)) ) { + if ( IS_DIGIT(*(s+i)) && *(s+i+1) != '\0' && i+1 != size ) { prev = 'd'; continue; } @@ -998,16 +977,16 @@ int uriIsIPv6( const char *s, int size, char **err ) { int octet = atoi(curSegmentStart); if ( octet > 255 ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "ipv4 portion octet %i is too high : %.*s", (ipv4portion), curSegmentLength, curSegmentStart ); + laaf_util_snprintf_realloc( err, NULL, 0, "ipv4 portion octet %i is too high : %.*s", (ipv4portion), curSegmentLength, curSegmentStart ); } return 0; } - // debug( "%i", octet ); + // debug( L"%i", octet ); if ( i+1 == size ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "can't end with a single '.'" ); + laaf_util_snprintf_realloc( err, NULL, 0, "can't end with a single '.'" ); } return 0; } @@ -1023,45 +1002,45 @@ int uriIsIPv6( const char *s, int size, char **err ) { } if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "illegal char '%c' (0x%02x)", *(s+i), *(s+i) ); + laaf_util_snprintf_realloc( err, NULL, 0, "illegal char '%c' (0x%02x)", *(s+i), *(s+i) ); } return 0; } - // debug( "segments : %i", segmentCount ); - // debug( "empty segments : %i", emptySegmentCount ); - // debug( "ipv4portion : %i", ipv4portion ); + // debug( L"segments : %i", segmentCount ); + // debug( L"empty segments : %i", emptySegmentCount ); + // debug( L"ipv4portion : %i", ipv4portion ); if ( ipv4portion > 4 ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "too many octets in ipv4 portion" ); + laaf_util_snprintf_realloc( err, NULL, 0, "too many octets in ipv4 portion : %i", ipv4portion ); } return 0; } if ( ipv4portion > 0 && ipv4portion < 4 ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "not enough octets in ipv4 portion" ); + laaf_util_snprintf_realloc( err, NULL, 0, "not enough octets in ipv4 portion : %i", ipv4portion ); } return 0; } if ( emptySegmentCount + (segmentCount/2) + ipv4portion > 8 ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "too many segments" ); + laaf_util_snprintf_realloc( err, NULL, 0, "too many segments" ); } return 0; } if ( emptySegmentCount == 0 && (((ipv4portion/2) + segmentCount) < 8) ) { if ( err ) { - _laaf_util_snprintf_realloc( err, NULL, 0, "not enough segments" ); + laaf_util_snprintf_realloc( err, NULL, 0, "not enough segments" ); } return 0; } - // debug( "LOCALHOST >>>>>>> %i", loopback ); + // debug( L"LOCALHOST >>>>>>> %i", loopback ); /* * 1: valid ipv6 address @@ -1096,271 +1075,3 @@ static void _uri_scheme2schemeType( struct uri *uri ) { else if ( strcmp( uri->scheme, "telnet" ) == 0 ) { uri->scheme_t = URI_SCHEME_T_TELNET; } else { uri->scheme_t = URI_SCHEME_T_UNKNOWN; } } - - - -static int _laaf_util_snprintf_realloc( char **str, size_t *size, size_t offset, const char *format, ... ) -{ - size_t tmpsize = 0; - - if ( !size ) { - size = &tmpsize; - } - - int retval, needed; - va_list ap; - - va_start( ap, format ); - - while ( 0 <= (retval = vsnprintf( (*str)+offset, (*size)-offset, format, ap )) - && (int64_t)((*size)-offset) < (needed = retval + 1)) - { - va_end( ap ); - - *size *= 2; - - if ( (int64_t)((*size)-offset) < needed ) - *size = needed; - - char *p = realloc( *str, *size ); - - if ( p ) { - *str = p; - } - else { - free( *str ); - *str = NULL; - *size = 0; - return -1; - } - - va_start( ap, format ); - } - - va_end( ap ); - - return retval; -} - - - -#ifdef BUILD_URI_TEST - -static int _uri_cmp( const struct uri *a, const struct uri *b ) { - - int differenciesCount = 0; - - if ( a == NULL || b == NULL ) { - return -1; - } - - // if ( (strcmp((a->scheme) ? a->scheme : "", (b->scheme) ? b->scheme : "") != 0 ) ) { - // differenciesCount++; - // } - if ( (strcmp((a->userinfo) ? a->userinfo : "", (b->userinfo) ? b->userinfo : "") != 0 ) ) { - differenciesCount++; - } - if ( (strcmp((a->user) ? a->user : "", (b->user) ? b->user : "") != 0 ) ) { - differenciesCount++; - } - if ( (strcmp((a->pass) ? a->pass : "", (b->pass) ? b->pass : "") != 0 ) ) { - differenciesCount++; - } - if ( (strcmp((a->host) ? a->host : "", (b->host) ? b->host : "") != 0 ) ) { - differenciesCount++; - } - if ( (strcmp((a->path) ? a->path : "", (b->path) ? b->path : "") != 0 ) ) { - differenciesCount++; - } - if ( (strcmp((a->query) ? a->query : "", (b->query) ? b->query : "") != 0 ) ) { - differenciesCount++; - } - if ( (strcmp((a->fragment) ? a->fragment : "", (b->fragment) ? b->fragment : "") != 0 ) ) { - differenciesCount++; - } - if ( a->port != b->port ) { - differenciesCount++; - } - if ( a->scheme_t != b->scheme_t ) { - differenciesCount++; - } - if ( a->flags != b->flags ) { - differenciesCount++; - } - - return differenciesCount; -} - - - -static void _uri_dump_diff( struct uri *a, struct uri *b, int totalDifferencies ) { - - int differenciesCount = 0; - - if ( a == NULL || b == NULL ) { - return; - } - - // if ( (strcmp((a->scheme) ? a->scheme : "", (b->scheme) ? b->scheme : "") != 0 ) ) { - // printf(" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .scheme : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->scheme, b->scheme ); - // } - if ( (strcmp((a->userinfo) ? a->userinfo : "", (b->userinfo) ? b->userinfo : "") != 0 ) ) { - printf(" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .userinfo : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->userinfo, b->userinfo ); - } - if ( (strcmp((a->user) ? a->user : "", (b->user) ? b->user : "") != 0 ) ) { - printf(" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .user : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->user, b->user ); - } - if ( (strcmp((a->pass) ? a->pass : "", (b->pass) ? b->pass : "") != 0 ) ) { - printf(" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .pass : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->pass, b->pass ); - } - if ( (strcmp((a->host) ? a->host : "", (b->host) ? b->host : "") != 0 ) ) { - printf(" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .host : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->host, b->host ); - } - if ( (strcmp((a->path) ? a->path : "", (b->path) ? b->path : "") != 0 ) ) { - printf(" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .path : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->path, b->path ); - } - if ( (strcmp((a->query) ? a->query : "", (b->query) ? b->query : "") != 0 ) ) { - printf(" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .query : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->query, b->query ); - } - if ( (strcmp((a->fragment) ? a->fragment : "", (b->fragment) ? b->fragment : "") != 0 ) ) { - printf(" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .fragment : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->fragment, b->fragment ); - } - - if ( a->port != b->port ) { - printf(" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .port : %i (expected: %i)\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->port, b->port ); - } - if ( a->scheme_t != b->scheme_t ) { - printf(" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .scheme_t : %i (expected: %i)\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->scheme_t, b->scheme_t ); - } - if ( a->flags != b->flags ) { - printf(" \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .flags : %i (expected: %i)\n", (++differenciesCount < totalDifferencies) ? "\u251c\u2500\u2500\u25fb" : "\u2514\u2500\u2500\u25fb", a->flags, b->flags ); - } -} - - - -static int _uri_test( const char *uristr, enum uri_option optflags, struct uri expectedRes, int line ) { - - struct uri *uri = uriParse( uristr, optflags ); - - int differenciesCount = 0; - - if ( (differenciesCount = _uri_cmp( uri, &expectedRes )) == 0 ) { - printf("\x1b[38;5;242m"); // dark gray - printf("%05i", line); - printf("\x1b[0m"); - - printf("\x1b[38;5;242m %s \x1b[0m", "\u2502" ); - - printf("\x1b[38;5;120m"); // green - printf("[ok] "); - printf("\x1b[0m"); - - printf("\x1b[38;5;242m"); // dark gray - printf("%s", uristr ); - printf("\x1b[0m"); - - printf("\n" ); - } - else { - printf("\x1b[38;5;124m"); // red - printf("%05i", line); - printf("\x1b[0m"); - - printf("\x1b[38;5;242m %s \x1b[0m", "\u2502" ); - - printf("\x1b[38;5;124m"); // red - printf("[er] "); - printf("\x1b[0m"); - - printf("\x1b[38;5;242m"); // dark gray - printf("%s", uristr ); - printf("\x1b[0m"); - - printf("\n" ); - - printf("\x1b[38;5;124m"); // red - _uri_dump_diff( uri, &expectedRes, differenciesCount ); - printf("\x1b[0m"); - - printf(" \x1b[38;5;242m\u2502\x1b[0m\n"); - } - - uriFree(uri); - - return differenciesCount; -} - - - -int main( void ) { - - int rc = 0; - - // rc += _uri_test( "", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_UNKNOWN, .host = NULL, .port = 0, .path = NULL, .query = NULL, .fragment = NULL }, __LINE__ ); - rc += _uri_test( "https://www.server.com", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://user:pass@www.server.com", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .userinfo = "user:pass", .user = "user", .pass = "pass", .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "HTTPS://www.server.com", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "hTtPs://www.server.com", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com:8080", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 8080, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com:8080?foo=bar", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 8080, .path = NULL, .query = "foo=bar", .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com:8080#anchor", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 8080, .path = NULL, .query = NULL, .fragment = "anchor", .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com/", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com/?foo=bar", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = "foo=bar", .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com/////?foo=bar", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = "foo=bar", .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com///////", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com?foo=bar", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = "foo=bar", .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com#anchor", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = "anchor", .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com/path/to/file.html?foo=bar&foo2=bar2#anchor", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/path/to/file.html", .query = "foo=bar&foo2=bar2", .fragment = "anchor", .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com:80/", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 80, .path = "/", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com:/", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com:", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - - rc += _uri_test( "https://[8:3:1:2:1234:5678::]:8080/ipv6", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "8:3:1:2:1234:5678::", .port = 8080, .path = "/ipv6", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 }, __LINE__ ); - rc += _uri_test( "https://[2001:db8:0:85a3::ac1f:8001]:8080/ipv6", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "2001:db8:0:85a3::ac1f:8001", .port = 8080, .path = "/ipv6", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 }, __LINE__ ); - rc += _uri_test( "https://user:pass@[2001:db8:3333:4444:5555:6666:1.2.3.4]:8080/ipv6", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .userinfo = "user:pass", .user = "user", .pass = "pass", .host = "2001:db8:3333:4444:5555:6666:1.2.3.4", .port = 8080, .path = "/ipv6", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 }, __LINE__ ); - rc += _uri_test( "https://192.168.0.1:8080/ipv4", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "192.168.0.1", .port = 8080, .path = "/ipv4", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV4 }, __LINE__ ); - rc += _uri_test( "https://127.0.0.1:8080/ipv4loopback", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "127.0.0.1", .port = 8080, .path = "/ipv4loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV4 | URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "https://localhost:8080/loopback", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "localhost", .port = 8080, .path = "/loopback", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "https://[0:0:0:0:0:0:0:1]:8080/ipv6loopback", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "0:0:0:0:0:0:0:1", .port = 8080, .path = "/ipv6loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 | URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "https://[::0:0:0:1]:8080/ipv6loopback", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "::0:0:0:1", .port = 8080, .path = "/ipv6loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 | URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "https://[::0:0000:0:001]:8080/ipv6loopback", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "::0:0000:0:001", .port = 8080, .path = "/ipv6loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 | URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "https://[::1]:8080/ipv6loopback", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "::1", .port = 8080, .path = "/ipv6loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 | URI_T_LOCALHOST }, __LINE__ ); - - rc += _uri_test( "https://user:pass@192.168.0.1:8080/ipv4", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .userinfo = "user:pass", .user = "user", .pass = "pass", .host = "192.168.0.1", .port = 8080, .path = "/ipv4", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV4 }, __LINE__ ); - - rc += _uri_test( "file://///C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "file:C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "file:/C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "file:///C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "file://?/C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "file://./C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); - - // Examples from AAF files external essences - rc += _uri_test( "file:///C:/Users/username/Downloads/441-16b.wav", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/Users/username/Downloads/441-16b.wav", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "file://?/E:/ADPAAF/Sequence A Rendu.mxf", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "E:/ADPAAF/Sequence A Rendu.mxf", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "file:////C:/Users/username/Desktop/TEST2977052.aaf", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/Users/username/Desktop/TEST2977052.aaf", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "file://localhost/Users/username/Music/fonk_2_3#04.wav", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = "localhost", .port = 0, .path = "/Users/username/Music/fonk_2_3#04.wav", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); - rc += _uri_test( "file://10.87.230.71/mixage/DR2/Avid MediaFiles/MXF/1/3572607.mxf", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = "10.87.230.71", .port = 0, .path = "/mixage/DR2/Avid MediaFiles/MXF/1/3572607.mxf", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV4 }, __LINE__ ); - rc += _uri_test( "file:///_system/Users/username/pt2MCCzmhsFRHQgdgsTMQX.mxf", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "/_system/Users/username/pt2MCCzmhsFRHQgdgsTMQX.mxf", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); - - // URL Percent Decoding - rc += _uri_test( "https://www.server.com/NON_DECODING/%C2%B0%2B%29%3D%C5%93%21%3A%3B%2C%3F.%2F%C2%A7%C3%B9%2A%24%C2%B5%C2%A3%7D%5D%E2%80%9C%23%7B%5B%7C%5E%40%5D%3C%3E", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/NON_DECODING/%C2%B0%2B%29%3D%C5%93%21%3A%3B%2C%3F.%2F%C2%A7%C3%B9%2A%24%C2%B5%C2%A3%7D%5D%E2%80%9C%23%7B%5B%7C%5E%40%5D%3C%3E", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com/DECODING/%C2%B0%2B%29%3D%C5%93%21%3A%3B%2C%3F.%2F%C2%A7%C3%B9%2A%24%C2%B5%C2%A3%7D%5D%E2%80%9C%23%7B%5B%7C%5E%40%5D%3C%3E", URI_OPT_DECODE_ALL, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/DECODING/°+)=œ!:;,?./§ù*$µ£}]“#{[|^@]<>", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - rc += _uri_test( "https://www.server.com/DECODING_UTF8/%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E7%B2%BE%E5%BA%A6%E7%B7%A8%E9%9B%86", URI_OPT_DECODE_ALL, (struct uri){ .scheme_t = URI_SCHEME_T_HTTPS, .userinfo = NULL, .user = NULL, .pass = NULL, .host = "www.server.com", .port = 0, .path = "/DECODING_UTF8/サンプル精度編集", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); - - // Examples from https://en.wikipedia.org/wiki/Uniform_Resource_Identifier - rc += _uri_test( "tel:+1-816-555-1212", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_TEL, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = "+1-816-555-1212", .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ ); - rc += _uri_test( "mailto:John.Doe@example.com", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_MAILTO, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = "John.Doe@example.com", .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ ); - rc += _uri_test( "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = "oasis:names:specification:docbook:dtd:xml:4.1.2", .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ ); - rc += _uri_test( "ldap://[2001:db8::7]/c=GB?objectClass?one", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = "2001:db8::7", .port = 0, .path = "/c=GB", .query = "objectClass?one", .fragment = NULL, .flags = URI_T_HOST_IPV6 }, __LINE__ ); - rc += _uri_test( "news:comp.infosystems.www.servers.unix", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = "comp.infosystems.www.servers.unix", .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ ); - - // rc += _uri_test( "xxxxxxxx", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ ); - // rc += _uri_test( "xxxxxxxx", URI_OPT_NONE, (struct uri){ .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ ); - - - return rc; -} - -#endif // BUILD_URI_TEST diff --git a/src/AAFIface/URIParser.h b/src/AAFIface/URIParser.h index ef6f09f..c120898 100644 --- a/src/AAFIface/URIParser.h +++ b/src/AAFIface/URIParser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Adrien Gesta-Fline + * Copyright (C) 2023-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -21,8 +21,17 @@ #ifndef URI_PARSER_H #define URI_PARSER_H -#include +#include +#if defined(__linux__) + #include + #include +#elif defined(__APPLE__) + #include +#elif defined(_WIN32) + #include // MAX_PATH + #include +#endif #define MAX_URI_LENGTH 64000 @@ -129,21 +138,9 @@ struct uri { -struct uri * uriParse( const char *, enum uri_option, struct dbg *dbg ); +struct uri * laaf_uri_parse( const char *, enum uri_option, struct aafLog *log ); -void uriFree( struct uri * ); - -/* - * if dst is NULL of equals src, then encoded source string will be overwritten - * by decoded string. - */ -char * uriDecodeString( char *src, char *dst ); - -char * uriDecodeWString( wchar_t *src, wchar_t *dst ); - -int uriIsIPv4( const char *s, int size, char **err ); - -int uriIsIPv6( const char *s, int size, char **err ); +void laaf_uri_free( struct uri * ); #endif // ! URI_PARSER_H diff --git a/src/LibCFB/CFBDump.c b/src/LibCFB/CFBDump.c index 939741d..41751a5 100644 --- a/src/LibCFB/CFBDump.c +++ b/src/LibCFB/CFBDump.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -21,8 +21,6 @@ #include #include #include -#include -#include #include #include @@ -30,18 +28,19 @@ #include + #define debug( ... ) \ - _dbg( cfbd->dbg, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_DEBUG, __VA_ARGS__ ) + AAF_LOG( cfbd->log, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_DEBUG, __VA_ARGS__ ) #define warning( ... ) \ - _dbg( cfbd->dbg, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_WARNING, __VA_ARGS__ ) + AAF_LOG( cfbd->log, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_WARNING, __VA_ARGS__ ) #define error( ... ) \ - _dbg( cfbd->dbg, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_ERROR, __VA_ARGS__ ) + AAF_LOG( cfbd->log, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_ERROR, __VA_ARGS__ ) -void cfb_dump_node( CFB_Data *cfbd, cfbNode *node, int print_stream ) +void cfb_dump_node( CFB_Data *cfbd, cfbNode *node, int print_stream, const char *padding ) { if ( node == NULL ) return; @@ -49,83 +48,92 @@ void cfb_dump_node( CFB_Data *cfbd, cfbNode *node, int print_stream ) if ( node->_mse == STGTY_INVALID ) return; - wchar_t nodeName[CFB_NODE_NAME_SZ]; - - cfb_w16towchar( nodeName, node->_ab, node->_cb ); + char *nodeName = cfb_w16toUTF8( node->_ab, node->_cb ); - struct dbg *dbg = cfbd->dbg; + struct aafLog *log = cfbd->log; - DBG_BUFFER_WRITE( dbg, "\n" ); - DBG_BUFFER_WRITE( dbg, " _ab : %ls\n", nodeName ); - DBG_BUFFER_WRITE( dbg, " _cb : %u\n", node->_cb ); - DBG_BUFFER_WRITE( dbg, " _mse : %s\n", + LOG_BUFFER_WRITE( log, "\n" ); + LOG_BUFFER_WRITE( log, "%s_ab : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), nodeName, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_cb : %s%u%s\n", padding, ANSI_COLOR_DARKGREY(log), node->_cb, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_mse : %s%s%s\n", + padding, + ANSI_COLOR_DARKGREY(log), node->_mse == 0 ? "STGTY_INVALID" : node->_mse == 1 ? "STGTY_STORAGE" : node->_mse == 2 ? "STGTY_STREAM" : node->_mse == 3 ? "STGTY_LOCKBYTES" : node->_mse == 4 ? "STGTY_PROPERTY" : - node->_mse == 5 ? "STGTY_ROOT" : "" ); + node->_mse == 5 ? "STGTY_ROOT" : "", + ANSI_COLOR_RESET(log) ); - DBG_BUFFER_WRITE( dbg, " _bflags : %s\n", node->_bflags == 1 ? "BLACK" : "RED" ); - DBG_BUFFER_WRITE( dbg, " _sidLeftSib : 0x%08x\n", node->_sidLeftSib ); - DBG_BUFFER_WRITE( dbg, " _sidRightSib : 0x%08x\n", node->_sidRightSib ); + LOG_BUFFER_WRITE( log, "%s_bflags : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), node->_bflags == 1 ? "BLACK" : "RED", ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_sidLeftSib : %s0x%08x%s\n", padding, ANSI_COLOR_DARKGREY(log), node->_sidLeftSib, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_sidRightSib : %s0x%08x%s\n", padding, ANSI_COLOR_DARKGREY(log), node->_sidRightSib, ANSI_COLOR_RESET(log) ); if ( node->_mse == STGTY_STORAGE || node->_mse == STGTY_ROOT ) { - DBG_BUFFER_WRITE( dbg, " _sidChild : 0x%08x\n", node->_sidChild ); - DBG_BUFFER_WRITE( dbg, " _clsid : %ls\n", cfb_CLSIDToText( &(node->_clsId) ) ); - DBG_BUFFER_WRITE( dbg, " _dwUserFlags : 0x%08x (%d)\n", node->_dwUserFlags, node->_dwUserFlags ); + LOG_BUFFER_WRITE( log, "%s_sidChild : %s0x%08x%s\n", padding, ANSI_COLOR_DARKGREY(log), node->_sidChild, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_clsid : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), cfb_CLSIDToText( &(node->_clsId) ), ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_dwUserFlags : %s0x%08x (%d)%s\n", padding, ANSI_COLOR_DARKGREY(log), node->_dwUserFlags, node->_dwUserFlags, ANSI_COLOR_RESET(log) ); } if ( node->_mse == STGTY_INVALID ) { - DBG_BUFFER_WRITE( dbg, " _time (cre) : 0x%08x%08x\n", + LOG_BUFFER_WRITE( log, "%s_time (cre) : %s0x%08x%08x%s\n", + padding, + ANSI_COLOR_DARKGREY(log), node->_time[0].dwHighDateTime, - node->_time[0].dwLowDateTime ); + node->_time[0].dwLowDateTime, + ANSI_COLOR_RESET(log) ); - DBG_BUFFER_WRITE( dbg, " _ (mod) : 0x%08x%08x\n", + LOG_BUFFER_WRITE( log, "%s_ (mod) : %s0x%08x%08x%s\n", + padding, + ANSI_COLOR_DARKGREY(log), node->_time[1].dwHighDateTime, - node->_time[1].dwLowDateTime ); + node->_time[1].dwLowDateTime, + ANSI_COLOR_RESET(log) ); } if ( node->_mse == STGTY_STREAM || node->_mse == STGTY_ROOT ) { - DBG_BUFFER_WRITE( dbg, " _sectStart : 0x%08x (%d)\n", node->_sectStart, node->_sectStart ); - DBG_BUFFER_WRITE( dbg, " _ulSizeLow : 0x%08x (%d)\n", node->_ulSizeLow, node->_ulSizeLow ); - DBG_BUFFER_WRITE( dbg, " _ulSizeHigh : 0x%08x (%d)\n", node->_ulSizeHigh, node->_ulSizeHigh ); + LOG_BUFFER_WRITE( log, "%s_sectStart : %s0x%08x (%d)%s\n", padding, ANSI_COLOR_DARKGREY(log), node->_sectStart, node->_sectStart, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_ulSizeLow : %s0x%08x (%d)%s\n", padding, ANSI_COLOR_DARKGREY(log), node->_ulSizeLow, node->_ulSizeLow, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_ulSizeHigh : %s0x%08x (%d)%s\n", padding, ANSI_COLOR_DARKGREY(log), node->_ulSizeHigh, node->_ulSizeHigh, ANSI_COLOR_RESET(log) ); } - DBG_BUFFER_WRITE( dbg, "\n\n" ); + LOG_BUFFER_WRITE( log, "\n\n" ); - dbg->debug_callback( dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + log->debug_callback( log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); if ( print_stream == 1 ) { - cfb_dump_nodeStream( cfbd, node ); + cfb_dump_nodeStream( cfbd, node, "" ); } + + free( nodeName ); } -void cfb_dump_nodePath( CFB_Data *cfbd, const wchar_t *path, int print_stream ) +void cfb_dump_nodePath( CFB_Data *cfbd, const char *path, int print_stream, const char *padding ) { cfbNode *node = cfb_getNodeByPath( cfbd, path, 0 ); if ( node == NULL ) { - error( "cfb_dump_nodePath() : Could not find node at \"%ls\"\n", path ); + error( "cfb_dump_nodePath() : Could not find node at \"%s\"\n", path ); return; } - cfb_dump_node( cfbd, node, print_stream ); + cfb_dump_node( cfbd, node, print_stream, padding ); } -void cfb_dump_nodeStream( CFB_Data *cfbd, cfbNode *node ) +void cfb_dump_nodeStream( CFB_Data *cfbd, cfbNode *node, const char *padding ) { - struct dbg *dbg = cfbd->dbg; + struct aafLog *log = cfbd->log; unsigned char *stream = NULL; uint64_t stream_sz = 0; @@ -136,23 +144,23 @@ void cfb_dump_nodeStream( CFB_Data *cfbd, cfbNode *node ) return; } - laaf_util_dump_hex( stream, stream_sz, &dbg->_dbg_msg, &dbg->_dbg_msg_size, dbg->_dbg_msg_pos ); + laaf_util_dump_hex( stream, stream_sz, &log->_msg, &log->_msg_size, log->_msg_pos, padding ); - dbg->debug_callback( dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + log->debug_callback( log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); free( stream ); } -void cfb_dump_nodePathStream( CFB_Data *cfbd, const wchar_t *path ) +void cfb_dump_nodePathStream( CFB_Data *cfbd, const char *path, const char *padding ) { - struct dbg *dbg = cfbd->dbg; + struct aafLog *log = cfbd->log; cfbNode *node = cfb_getNodeByPath( cfbd, path, 0 ); if ( node == NULL ) { - error( "cfb_dump_nodePathStream() : Could not find node at \"%ls\"\n", path ); + error( "Could not find node at \"%s\"\n", path ); return; } @@ -161,216 +169,278 @@ void cfb_dump_nodePathStream( CFB_Data *cfbd, const wchar_t *path ) cfb_getStream( cfbd, node, &stream, &stream_sz ); - laaf_util_dump_hex( stream, stream_sz, &dbg->_dbg_msg, &dbg->_dbg_msg_size, dbg->_dbg_msg_pos ); + laaf_util_dump_hex( stream, stream_sz, &log->_msg, &log->_msg_size, log->_msg_pos, padding ); - dbg->debug_callback( dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + log->debug_callback( log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); free( stream ); } -void cfb_dump_nodePaths( CFB_Data *cfbd, uint32_t prevPath, char *strArray[], uint32_t *str_i, cfbNode *node ) +void cfb_dump_nodePaths( CFB_Data *cfbd, uint32_t prevPath, char *strArray[], uint32_t *str_i, cfbNode *node, const char *padding, int firstIteration ) { - struct dbg *dbg = cfbd->dbg; + struct aafLog *log = cfbd->log; - if ( node == NULL ) { - /* the begining of the first function call. */ + // if ( !node ) { + if ( firstIteration ) { + /* initial function call */ node = &cfbd->nodes[0]; - strArray = calloc( cfbd->nodes_cnt, sizeof(char*) ); - } + if ( !node ) { + return; + } - uint32_t thisPath = (*str_i); - wchar_t nodeName[CFB_NODE_NAME_SZ]; + strArray = calloc( cfbd->nodes_cnt, sizeof(char*) ); - cfb_w16towchar( nodeName, node->_ab, node->_cb ); + if ( !strArray ) { + error( "Out of memory" ); + return; + } + } - int pathlen = snprintf( NULL, 0, "%s/%ls", strArray[prevPath], nodeName ); - if ( pathlen < 0 ) { - // TODO error - return; - } + uint32_t thisPath = (*str_i); - pathlen++; + /* TODO snprintf_realloc() ? */ + char *nodeName = cfb_w16toUTF8( node->_ab, node->_cb ); - strArray[thisPath] = malloc( pathlen ); + laaf_util_snprintf_realloc( &strArray[thisPath], 0, 0, "%s/%s", strArray[prevPath], nodeName ); - snprintf( strArray[thisPath], pathlen, "%s/%ls", strArray[prevPath], nodeName ); + free( nodeName ); (*str_i)++; if ( (int32_t)node->_sidChild > 0 ) - cfb_dump_nodePaths( cfbd, thisPath, strArray, str_i, &cfbd->nodes[node->_sidChild] ); + cfb_dump_nodePaths( cfbd, thisPath, strArray, str_i, &cfbd->nodes[node->_sidChild], padding, 0 ); if ( (int32_t)node->_sidLeftSib > 0 ) - cfb_dump_nodePaths( cfbd, prevPath, strArray, str_i, &cfbd->nodes[node->_sidLeftSib] ); + cfb_dump_nodePaths( cfbd, prevPath, strArray, str_i, &cfbd->nodes[node->_sidLeftSib], padding, 0 ); if ( (int32_t)node->_sidRightSib > 0 ) - cfb_dump_nodePaths( cfbd, prevPath, strArray, str_i, &cfbd->nodes[node->_sidRightSib] ); + cfb_dump_nodePaths( cfbd, prevPath, strArray, str_i, &cfbd->nodes[node->_sidRightSib], padding, 0 ); /* the end of the first function call, recursion is over. */ - if ( node == &cfbd->nodes[0] ) { + // if ( node == &cfbd->nodes[0] ) { + if ( firstIteration ) { - /* commented out because output is proper this way... why did we call qsort() in the first place ?! */ + /* commented out because output seems proper this way... why did we call qsort() in the first place ?! */ // qsort( strArray, *str_i, sizeof(char*), compareStrings ); for ( uint32_t i = 0; i < cfbd->nodes_cnt && strArray[i] != NULL; i++ ) { - DBG_BUFFER_WRITE( dbg, "%05i : %s\n", i, strArray[i] ); + LOG_BUFFER_WRITE( log, "%s%0*i : %s%s%s\n", + padding, + (cfbd->nodes_cnt>1000000) ? 7 : + (cfbd->nodes_cnt>100000) ? 6 : + (cfbd->nodes_cnt>10000) ? 5 : + (cfbd->nodes_cnt>1000) ? 4 : + (cfbd->nodes_cnt>100) ? 3 : + (cfbd->nodes_cnt>10) ? 2 : 1, + i, + ANSI_COLOR_DARKGREY(log), + strArray[i], + ANSI_COLOR_RESET(log) ); free( strArray[i] ); } free( strArray ); - DBG_BUFFER_WRITE( dbg, "\n\n" ); + LOG_BUFFER_WRITE( log, "\n\n" ); - dbg->debug_callback( dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + log->debug_callback( log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); } } -void cfb_dump_header( CFB_Data *cfbd ) +void cfb_dump_header( CFB_Data *cfbd, const char *padding ) { - struct dbg *dbg = cfbd->dbg; + struct aafLog *log = cfbd->log; cfbHeader *cfbh = cfbd->hdr; - DBG_BUFFER_WRITE( dbg, "_abSig : 0x%08"PRIx64"\n", cfbh->_abSig ); - DBG_BUFFER_WRITE( dbg, "_clsId : %ls\n", cfb_CLSIDToText( &(cfbh->_clsid) ) ); - DBG_BUFFER_WRITE( dbg, " version : %u.%u ( 0x%04x 0x%04x )\n", + LOG_BUFFER_WRITE( log, "%s_abSig : %s0x%08"PRIx64"%s\n", padding, ANSI_COLOR_DARKGREY(log), cfbh->_abSig, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_clsId : %s%s%s\n", padding, ANSI_COLOR_DARKGREY(log), cfb_CLSIDToText( &(cfbh->_clsid) ), ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_version : %s%u.%u ( 0x%04x 0x%04x )%s\n", + padding, + ANSI_COLOR_DARKGREY(log), cfbh->_uMinorVersion, cfbh->_uDllVersion, - cfbh->_uMinorVersion, cfbh->_uDllVersion ); - DBG_BUFFER_WRITE( dbg, "_uByteOrder : %s ( 0x%04x )\n", + cfbh->_uMinorVersion, cfbh->_uDllVersion, + ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_uByteOrder : %s%s ( 0x%04x )%s\n", + padding, + ANSI_COLOR_DARKGREY(log), cfbh->_uByteOrder == 0xFFFE ? "little-endian" : cfbh->_uByteOrder == 0xFEFF ? "big-endian" : "?", - cfbh->_uByteOrder ); - DBG_BUFFER_WRITE( dbg, "_uSectorShift : %u (%u bytes sectors)\n", + cfbh->_uByteOrder, + ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_uSectorShift : %s%u (%u bytes sectors)%s\n", + padding, + ANSI_COLOR_DARKGREY(log), cfbh->_uSectorShift, - 1<_uSectorShift ); - DBG_BUFFER_WRITE( dbg, "_uMiniSectorShift : %u (%u bytes mini-sectors)\n", + 1<_uSectorShift, + ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_uMiniSectorShift : %s%u (%u bytes mini-sectors)%s\n", + padding, + ANSI_COLOR_DARKGREY(log), cfbh->_uMiniSectorShift, - 1<_uMiniSectorShift ); - DBG_BUFFER_WRITE( dbg, "_usReserved0 : 0x%02x\n", cfbh->_usReserved ); - DBG_BUFFER_WRITE( dbg, "_ulReserved1 : 0x%04x\n", cfbh->_ulReserved1 ); - DBG_BUFFER_WRITE( dbg, "_csectDir : %u\n", cfbh->_csectDir ); - DBG_BUFFER_WRITE( dbg, "_csectFat : %u\n", cfbh->_csectFat ); - DBG_BUFFER_WRITE( dbg, "_sectDirStart : %u\n", cfbh->_sectDirStart ); - DBG_BUFFER_WRITE( dbg, "_signature : %u\n", cfbh->_signature ); - DBG_BUFFER_WRITE( dbg, "_ulMiniSectorCutoff : %u\n", cfbh->_ulMiniSectorCutoff ); - DBG_BUFFER_WRITE( dbg, "_sectMiniFatStart : %u\n", cfbh->_sectMiniFatStart ); - DBG_BUFFER_WRITE( dbg, "_csectMiniFat : %u\n", cfbh->_csectMiniFat ); - DBG_BUFFER_WRITE( dbg, "_sectDifStart : %u\n", cfbh->_sectDifStart ); - DBG_BUFFER_WRITE( dbg, "_csectDif : %u\n", cfbh->_csectDif ); - - DBG_BUFFER_WRITE( dbg, "\n" ); - - dbg->debug_callback( dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + 1<_uMiniSectorShift, + ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_usReserved0 : %s0x%02x%s\n", padding, ANSI_COLOR_DARKGREY(log), cfbh->_usReserved, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_ulReserved1 : %s0x%04x%s\n", padding, ANSI_COLOR_DARKGREY(log), cfbh->_ulReserved1, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_csectDir : %s%u%s\n", padding, ANSI_COLOR_DARKGREY(log), cfbh->_csectDir, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_csectFat : %s%u%s\n", padding, ANSI_COLOR_DARKGREY(log), cfbh->_csectFat, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_sectDirStart : %s%u%s\n", padding, ANSI_COLOR_DARKGREY(log), cfbh->_sectDirStart, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_signature : %s%u%s\n", padding, ANSI_COLOR_DARKGREY(log), cfbh->_signature, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_ulMiniSectorCutoff : %s%u%s\n", padding, ANSI_COLOR_DARKGREY(log), cfbh->_ulMiniSectorCutoff, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_sectMiniFatStart : %s%u%s\n", padding, ANSI_COLOR_DARKGREY(log), cfbh->_sectMiniFatStart, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_csectMiniFat : %s%u%s\n", padding, ANSI_COLOR_DARKGREY(log), cfbh->_csectMiniFat, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_sectDifStart : %s%u%s\n", padding, ANSI_COLOR_DARKGREY(log), cfbh->_sectDifStart, ANSI_COLOR_RESET(log) ); + LOG_BUFFER_WRITE( log, "%s_csectDif : %s%u%s\n", padding, ANSI_COLOR_DARKGREY(log), cfbh->_csectDif, ANSI_COLOR_RESET(log) ); + + LOG_BUFFER_WRITE( log, "\n" ); + + log->debug_callback( log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); } -void cfb_dump_FAT( CFB_Data *cfbd ) +void cfb_dump_FAT( CFB_Data *cfbd, const char *padding ) { - struct dbg *dbg = cfbd->dbg; + struct aafLog *log = cfbd->log; - DBG_BUFFER_WRITE( dbg, "_CFB_FAT_______________________________________________________________________________________\n\n" ); + LOG_BUFFER_WRITE( log, "_CFB_FAT_______________________________________________________________________________________\n\n" ); uint32_t i = 0; for ( i = 0; i < cfbd->fat_sz; i++ ) { - DBG_BUFFER_WRITE( dbg, " SECT[%u] : 0x%08x %s\n", + LOG_BUFFER_WRITE( log, "%sSECT[%s%0*u%s] : %s0x%08x %s%s\n", + padding, + ANSI_COLOR_DARKGREY(log), + (cfbd->fat_sz>1000000) ? 7 : + (cfbd->fat_sz>100000) ? 6 : + (cfbd->fat_sz>10000) ? 5 : + (cfbd->fat_sz>1000) ? 4 : + (cfbd->fat_sz>100) ? 3 : + (cfbd->fat_sz>10) ? 2 : 1, i, + ANSI_COLOR_RESET(log), + + ANSI_COLOR_DARKGREY(log), cfbd->fat[i], ( cfbd->fat[i] == CFB_MAX_REG_SECT ) ? "(CFB_MAX_REG_SECT)" : ( cfbd->fat[i] == CFB_DIFAT_SECT ) ? "(CFB_DIFAT_SECT)" : ( cfbd->fat[i] == CFB_FAT_SECT ) ? "(CFB_FAT_SECT)" : ( cfbd->fat[i] == CFB_END_OF_CHAIN ) ? "(CFB_END_OF_CHAIN)" : ( cfbd->fat[i] == CFB_FREE_SECT ) ? "(CFB_FREE_SECT)" : - "" ); + "", + ANSI_COLOR_RESET(log) ); } - DBG_BUFFER_WRITE( dbg, "\n" ); + LOG_BUFFER_WRITE( log, "\n" ); - DBG_BUFFER_WRITE( dbg, " End of FAT.\n\n" ); + LOG_BUFFER_WRITE( log, "%sEnd of FAT.\n\n", padding ); - DBG_BUFFER_WRITE( dbg, " Total FAT entries : %u\n", cfbd->fat_sz ); - DBG_BUFFER_WRITE( dbg, " Count of FAT sector : %u\n", cfbd->hdr->_csectFat ); + LOG_BUFFER_WRITE( log, "%sTotal FAT entries : %u\n", padding, cfbd->fat_sz ); + LOG_BUFFER_WRITE( log, "%sCount of FAT sector : %u\n", padding, cfbd->hdr->_csectFat ); - DBG_BUFFER_WRITE( dbg, "\n\n" ); + LOG_BUFFER_WRITE( log, "\n\n" ); - dbg->debug_callback( dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + log->debug_callback( log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); } -void cfb_dump_MiniFAT( CFB_Data *cfbd ) +void cfb_dump_MiniFAT( CFB_Data *cfbd, const char *padding ) { - struct dbg *dbg = cfbd->dbg; + struct aafLog *log = cfbd->log; - DBG_BUFFER_WRITE( dbg, "_CFB_MiniFAT___________________________________________________________________________________\n\n" ); + LOG_BUFFER_WRITE( log, "_CFB_MiniFAT___________________________________________________________________________________\n\n" ); uint32_t i = 0; for ( i = 0; i < cfbd->miniFat_sz; i++ ) { - DBG_BUFFER_WRITE( dbg, " SECT[%u] : 0x%08x %s\n", + LOG_BUFFER_WRITE( log, "%sSECT[%s%0*u%s] : %s0x%08x %s%s\n", + padding, + ANSI_COLOR_DARKGREY(log), + (cfbd->miniFat_sz>1000000) ? 7 : + (cfbd->miniFat_sz>100000) ? 6 : + (cfbd->miniFat_sz>10000) ? 5 : + (cfbd->miniFat_sz>1000) ? 4 : + (cfbd->miniFat_sz>100) ? 3 : + (cfbd->miniFat_sz>10) ? 2 : 1, i, + ANSI_COLOR_RESET(log), + + ANSI_COLOR_DARKGREY(log), cfbd->miniFat[i], ( cfbd->miniFat[i] == CFB_MAX_REG_SECT ) ? "(CFB_MAX_REG_SECT)" : ( cfbd->miniFat[i] == CFB_DIFAT_SECT ) ? "(CFB_DIFAT_SECT)" : ( cfbd->miniFat[i] == CFB_FAT_SECT ) ? "(CFB_FAT_SECT)" : ( cfbd->miniFat[i] == CFB_END_OF_CHAIN ) ? "(CFB_END_OF_CHAIN)" : ( cfbd->miniFat[i] == CFB_FREE_SECT ) ? "(CFB_FREE_SECT)" : - "" ); + "", + ANSI_COLOR_RESET(log) ); } - DBG_BUFFER_WRITE( dbg, "\n" ); + LOG_BUFFER_WRITE( log, "\n" ); - DBG_BUFFER_WRITE( dbg, " End of MiniFAT.\n\n" ); + LOG_BUFFER_WRITE( log, "%sEnd of MiniFAT.\n\n", padding ); - DBG_BUFFER_WRITE( dbg, " Total MiniFAT entries : %u\n", cfbd->miniFat_sz ); - DBG_BUFFER_WRITE( dbg, " First MiniFAT sector ID : %u\n", cfbd->hdr->_sectMiniFatStart ); - DBG_BUFFER_WRITE( dbg, " Count of MiniFAT sector : %u\n", cfbd->hdr->_csectMiniFat ); + LOG_BUFFER_WRITE( log, "%sTotal MiniFAT entries : %u\n", padding, cfbd->miniFat_sz ); + LOG_BUFFER_WRITE( log, "%sFirst MiniFAT sector ID : %u\n", padding, cfbd->hdr->_sectMiniFatStart ); + LOG_BUFFER_WRITE( log, "%sCount of MiniFAT sector : %u\n", padding, cfbd->hdr->_csectMiniFat ); - DBG_BUFFER_WRITE( dbg, "\n\n" ); + LOG_BUFFER_WRITE( log, "\n\n" ); - dbg->debug_callback( dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + log->debug_callback( log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); } -void cfb_dump_DiFAT( CFB_Data *cfbd ) +void cfb_dump_DiFAT( CFB_Data *cfbd, const char *padding ) { - struct dbg *dbg = cfbd->dbg; + struct aafLog *log = cfbd->log; - DBG_BUFFER_WRITE( dbg, "_CFB_DiFAT_____________________________________________________________________________________\n\n" ); + LOG_BUFFER_WRITE( log, "_CFB_DiFAT_____________________________________________________________________________________\n\n" ); uint32_t i = 0; for ( i = 0; i < cfbd->DiFAT_sz; i++ ) { - DBG_BUFFER_WRITE( dbg, " SECT[%u] : 0x%08x %s\n", + LOG_BUFFER_WRITE( log, "%sSECT[%s%0*u%s] : %s0x%08x %s%s\n", + padding, + ANSI_COLOR_DARKGREY(log), + (cfbd->miniFat_sz>1000000) ? 7 : + (cfbd->miniFat_sz>100000) ? 6 : + (cfbd->miniFat_sz>10000) ? 5 : + (cfbd->miniFat_sz>1000) ? 4 : + (cfbd->miniFat_sz>100) ? 3 : + (cfbd->miniFat_sz>10) ? 2 : 1, i, + ANSI_COLOR_RESET(log), + + ANSI_COLOR_DARKGREY(log), cfbd->DiFAT[i], ( cfbd->DiFAT[i] == CFB_MAX_REG_SECT ) ? "(CFB_MAX_REG_SECT)" : ( cfbd->DiFAT[i] == CFB_DIFAT_SECT ) ? "(CFB_DIFAT_SECT)" : ( cfbd->DiFAT[i] == CFB_FAT_SECT ) ? "(CFB_FAT_SECT)" : ( cfbd->DiFAT[i] == CFB_END_OF_CHAIN ) ? "(CFB_END_OF_CHAIN)" : ( cfbd->DiFAT[i] == CFB_FREE_SECT ) ? "(CFB_FREE_SECT)" : - "" ); + "", + ANSI_COLOR_RESET(log) ); } - DBG_BUFFER_WRITE( dbg, "\n" ); + LOG_BUFFER_WRITE( log, "\n" ); - DBG_BUFFER_WRITE( dbg, " End of DiFAT.\n\n" ); + LOG_BUFFER_WRITE( log, "%sEnd of DiFAT.\n\n", padding ); - DBG_BUFFER_WRITE( dbg, " Total DiFAT entries : %u\n", cfbd->DiFAT_sz ); - DBG_BUFFER_WRITE( dbg, " First DiFAT sector ID : %u\n", cfbd->hdr->_sectDifStart ); - DBG_BUFFER_WRITE( dbg, " Count of DiFAT sector : Header + %u\n", cfbd->hdr->_csectDif ); + LOG_BUFFER_WRITE( log, "%sTotal DiFAT entries : %u\n", padding, cfbd->DiFAT_sz ); + LOG_BUFFER_WRITE( log, "%sFirst DiFAT sector ID : %u\n", padding, cfbd->hdr->_sectDifStart ); + LOG_BUFFER_WRITE( log, "%sCount of DiFAT sector : Header + %u\n", padding, cfbd->hdr->_csectDif ); - DBG_BUFFER_WRITE( dbg, "\n\n" ); + LOG_BUFFER_WRITE( log, "\n\n" ); - dbg->debug_callback( dbg, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, dbg->_dbg_msg, dbg->user ); + log->debug_callback( log, (void*)cfbd, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); } diff --git a/src/LibCFB/LibCFB.c b/src/LibCFB/LibCFB.c index 98dd1d4..2f10c5f 100644 --- a/src/LibCFB/LibCFB.c +++ b/src/LibCFB/LibCFB.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -55,7 +55,7 @@ * * Once the file is loaded, you can access the nodes with the functions * cfb_getNodeByPath() and cfb_getChildNode(), and access a node's stream with the - * functions cfb_getStream() or cfb_foreachSectorInStream(). The former is prefered + * functions cfb_getStream() or CFB_foreachSectorInStream(). The former is prefered * for small-size streams, since it allocates the entire stream to memory, while the * later loops through each sector that composes a stream, better for the big ones. * @@ -79,7 +79,7 @@ * // Loop through each sector that composes the "properties" stream * cfbSectorID_t sectorID = 0; * - * cfb_foreachSectorInStream( cfbd, properties, &stream, &stream_sz, §orID ) + * CFB_foreachSectorInStream( cfbd, properties, &stream, &stream_sz, §orID ) * { * // do stuff.. * } @@ -101,22 +101,23 @@ #include #include // ceil() #include -#include +#include #include -#include +#include #include #define debug( ... ) \ - _dbg( cfbd->dbg, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_DEBUG, __VA_ARGS__ ) + AAF_LOG( cfbd->log, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_DEBUG, __VA_ARGS__ ) #define warning( ... ) \ - _dbg( cfbd->dbg, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_WARNING, __VA_ARGS__ ) + AAF_LOG( cfbd->log, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_WARNING, __VA_ARGS__ ) #define error( ... ) \ - _dbg( cfbd->dbg, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_ERROR, __VA_ARGS__ ) + AAF_LOG( cfbd->log, cfbd, DEBUG_SRC_ID_LIB_CFB, VERB_ERROR, __VA_ARGS__ ) + @@ -124,7 +125,7 @@ static int cfb_getFileSize( CFB_Data *cfbd ); static int cfb_openFile( CFB_Data *cfbd ); -static uint64_t cfb_readFile( CFB_Data *cfbd, unsigned char *buf, uint64_t offset, uint64_t len ); +static uint64_t cfb_readFile( CFB_Data *cfbd, unsigned char *buf, size_t offset, size_t len ); static void cfb_closeFile( CFB_Data *cfbd ); @@ -149,9 +150,9 @@ static cfbSID_t cfb_getIDByNode( CFB_Data *cfbd, cfbNode *node ); -const wchar_t * cfb_CLSIDToText( const cfbCLSID_t *clsid ) +const char * cfb_CLSIDToText( const cfbCLSID_t *clsid ) { - static wchar_t str[96]; + static char str[96]; if ( clsid == NULL ) { str[0] = 'n'; @@ -160,7 +161,7 @@ const wchar_t * cfb_CLSIDToText( const cfbCLSID_t *clsid ) str[3] = '\0'; } else { - swprintf( str, sizeof(str), L"{ 0x%08x 0x%04x 0x%04x { 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x } }", + int rc = snprintf( str, sizeof(str), "{ 0x%08x 0x%04x 0x%04x { 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x } }", clsid->Data1, clsid->Data2, clsid->Data3, @@ -172,6 +173,11 @@ const wchar_t * cfb_CLSIDToText( const cfbCLSID_t *clsid ) clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); + + if ( rc < 0 || (size_t)rc >= sizeof(str) ) { + // TODO error + return NULL; + } } return str; @@ -185,16 +191,15 @@ const wchar_t * cfb_CLSIDToText( const cfbCLSID_t *clsid ) * @return Pointer to the newly allocated CFB_Data structure. */ -CFB_Data * cfb_alloc( struct dbg *dbg ) +CFB_Data * cfb_alloc( struct aafLog *log ) { - CFB_Data * cfbd = calloc( sizeof(CFB_Data), sizeof(unsigned char) ); + CFB_Data * cfbd = calloc( 1, sizeof(CFB_Data) ); - if ( cfbd == NULL ) { - error( "%s.", strerror(errno) ); + if ( !cfbd ) { return NULL; } - cfbd->dbg = dbg; + cfbd->log = log; return cfbd; } @@ -215,30 +220,23 @@ void cfb_release( CFB_Data **cfbd ) cfb_closeFile( *cfbd ); - if ( (*cfbd)->DiFAT != NULL ) { - free( (*cfbd)->DiFAT ); - (*cfbd)->DiFAT = NULL; - } + free( (*cfbd)->file ); + (*cfbd)->file = NULL; - if ( (*cfbd)->fat != NULL ) { - free( (*cfbd)->fat ); - (*cfbd)->fat = NULL; - } + free( (*cfbd)->DiFAT ); + (*cfbd)->DiFAT = NULL; - if ( (*cfbd)->miniFat != NULL ) { - free( (*cfbd)->miniFat ); - (*cfbd)->miniFat = NULL; - } + free( (*cfbd)->fat ); + (*cfbd)->fat = NULL; - if ( (*cfbd)->nodes != NULL ) { - free( (*cfbd)->nodes ); - (*cfbd)->nodes = NULL; - } + free( (*cfbd)->miniFat ); + (*cfbd)->miniFat = NULL; - if ( (*cfbd)->hdr != NULL ) { - free( (*cfbd)->hdr ); - (*cfbd)->hdr = NULL; - } + free( (*cfbd)->nodes ); + (*cfbd)->nodes = NULL; + + free( (*cfbd)->hdr ); + (*cfbd)->hdr = NULL; free( *cfbd ); *cfbd = NULL; @@ -259,10 +257,12 @@ void cfb_release( CFB_Data **cfbd ) * 1 on error */ -int cfb_load_file( CFB_Data **cfbd_p, const char * file ) +int cfb_load_file( CFB_Data **cfbd_p, const char *file ) { CFB_Data *cfbd = *cfbd_p; - snprintf( cfbd->file, sizeof(((CFB_Data){0}).file), "%s", file ); + + // laaf_util_snprintf_realloc( &cfbd->file, NULL, 0, "%s", file ); + cfbd->file = laaf_util_absolute_path( file ); if ( cfb_openFile( cfbd ) < 0 ) { @@ -310,6 +310,12 @@ int cfb_load_file( CFB_Data **cfbd_p, const char * file ) return -1; } + + // debug( "FAT size: %u", cfbd->fat_sz ); + // debug( "DiFAT size: %u", cfbd->DiFAT_sz ); + // debug( "MiniFAT size: %u", cfbd->miniFat_sz ); + // debug( "MiniFAT sector (%u) per FAT setor (%u): %u", (1 << cfbd->hdr->_uMiniSectorShift), (1 << cfbd->hdr->_uSectorShift), (1 << cfbd->hdr->_uSectorShift) / (1 << cfbd->hdr->_uMiniSectorShift) ); + return 0; } @@ -328,11 +334,13 @@ int cfb_new_file( CFB_Data *cfbd, const char *file, int sectSize ) cfbHeader *hdr = malloc( sizeof(cfbHeader) ); - if ( cfbd->hdr == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !hdr ) { + error( "Out of memory" ); return -1; } + cfbd->hdr = hdr; + hdr->_abSig = 0xe11ab1a1e011cfd0; /* @@ -411,23 +419,37 @@ static int cfb_is_valid( CFB_Data *cfbd ) static int cfb_getFileSize( CFB_Data * cfbd ) { + +#ifdef _WIN32 + if ( _fseeki64( cfbd->fp, 0L, SEEK_END ) < 0 ) { + error( "fseek() failed : %s.", strerror(errno) ); + return -1; + } + + __int64 filesz = _ftelli64( cfbd->fp ); + +#else if ( fseek( cfbd->fp, 0L, SEEK_END ) < 0 ) { error( "fseek() failed : %s.", strerror(errno) ); return -1; } - cfbd->file_sz = ftell( cfbd->fp ); + long filesz = ftell( cfbd->fp ); + +#endif - if ( (long)cfbd->file_sz < 0 ) { + if ( filesz < 0 ) { error( "ftell() failed : %s.", strerror(errno) ); return -1; } - if ( cfbd->file_sz == 0 ) { + if ( filesz == 0 ) { error( "File is empty (0 byte)." ); return -1; } + cfbd->file_sz = (size_t)filesz; + return 0; } @@ -442,9 +464,28 @@ static int cfb_getFileSize( CFB_Data * cfbd ) static int cfb_openFile( CFB_Data *cfbd ) { + if ( !cfbd->file ) { + return -1; + } + +#ifdef _WIN32 + + wchar_t *wfile = laaf_util_windows_utf8toutf16( cfbd->file ); + + if ( !wfile ) { + error( "Unable to convert filepath to wide string : %s", cfbd->file ); + return -1; + } + + cfbd->fp = _wfopen( wfile, L"rb" ); + + free( wfile ); + +#else cfbd->fp = fopen( cfbd->file, "rb" ); +#endif - if ( cfbd->fp == NULL ) { + if ( !cfbd->fp ) { error( "%s.", strerror(errno) ); return -1; } @@ -465,18 +506,23 @@ static int cfb_openFile( CFB_Data *cfbd ) * @param len Number of bytes to read from the offset position. */ -static uint64_t cfb_readFile( CFB_Data *cfbd, unsigned char *buf, uint64_t offset, uint64_t len ) +static uint64_t cfb_readFile( CFB_Data *cfbd, unsigned char *buf, size_t offset, size_t reqlen ) { FILE *fp = cfbd->fp; + // debug( "Requesting file read @ offset %"PRIu64" of length %"PRIu64, offset, reqlen ); - if ( len + offset > cfbd->file_sz ) { - error( "Requested data goes %"PRIu64" bytes beyond the EOF : offset %"PRIu64" | length %"PRIu64"", (len + offset) - cfbd->file_sz, offset, len ); + if ( offset >= LONG_MAX ) { + error( "Requested data offset is bigger than LONG_MAX" ); return 0; } + if ( reqlen + offset > cfbd->file_sz ) { + error( "Requested data goes %"PRIu64" bytes beyond the EOF : offset %"PRIu64" | length %"PRIu64"", (reqlen + offset) - cfbd->file_sz, offset, reqlen ); + return 0; + } - int rc = fseek( fp, offset, SEEK_SET ); + int rc = fseek( fp, (long)offset, SEEK_SET ); if ( rc < 0 ) { error( "%s.", strerror(errno) ); @@ -484,12 +530,22 @@ static uint64_t cfb_readFile( CFB_Data *cfbd, unsigned char *buf, uint64_t offse } - uint64_t byteRead = fread( buf, sizeof(unsigned char), len, fp ); + size_t byteRead = fread( buf, sizeof(unsigned char), reqlen, fp ); - if ( byteRead < len ) { - warning( "Could only retrieve %"PRIu64" bytes out of %"PRIu64" requested.", byteRead, len ); + if ( feof(fp) ) { + if ( byteRead < reqlen ) { + error( "Incomplete fread() of CFB due to EOF : %"PRIu64" bytes read out of %"PRIu64" requested", byteRead, reqlen ); + } + debug( "fread() : EOF reached in CFB file" ); + } + else if ( ferror(fp) ) { + if ( byteRead < reqlen ) { + error( "Incomplete fread() of CFB due to error : %"PRIu64" bytes read out of %"PRIu64" requested", byteRead, reqlen ); + } + else { + error( "fread() error of CFB : %"PRIu64" bytes read out of %"PRIu64" requested", byteRead, reqlen ); + } } - return byteRead; } @@ -535,33 +591,30 @@ unsigned char * cfb_getSector( CFB_Data *cfbd, cfbSectorID_t id ) if ( id >= CFB_MAX_REG_SID ) return NULL; - if ( cfbd->fat_sz > 0 && id >= cfbd->fat_sz ) { error( "Asking for an out of range FAT sector @ index %u (max FAT index is %u)", id, cfbd->fat_sz ); return NULL; } - uint64_t sectorSize = (1 << cfbd->hdr->_uSectorShift); uint64_t fileOffset = (id + 1) << cfbd->hdr->_uSectorShift; + unsigned char *buf = calloc( 1, sectorSize ); - unsigned char *buf = calloc( sectorSize, sizeof(unsigned char) ); - - if ( buf == NULL ) { - error( "%s.", strerror(errno) ); + if ( !buf ) { + error( "Out of memory" ); return NULL; } - if ( cfb_readFile( cfbd, buf, fileOffset, sectorSize ) == 0 ) { free( buf ); return NULL; } + // laaf_util_dump_hex( buf, (1<hdr->_uSectorShift), &cfbd->log->_msg, &cfbd->log->_msg_size, cfbd->log->_msg_pos, "" ); return buf; } @@ -593,15 +646,15 @@ unsigned char * cfb_getMiniSector( CFB_Data *cfbd, cfbSectorID_t id ) return NULL; } - int MiniSectorSize = 1 << cfbd->hdr->_uMiniSectorShift; - int SectorSize = 1 << cfbd->hdr->_uSectorShift; + uint32_t SectorSize = 1 << cfbd->hdr->_uSectorShift; + uint32_t MiniSectorSize = 1 << cfbd->hdr->_uMiniSectorShift; - unsigned char * buf = calloc( MiniSectorSize, sizeof(unsigned char) ); + unsigned char * buf = calloc( 1, MiniSectorSize ); - if ( buf == NULL ) { - error( "%s.", strerror(errno) ); + if ( !buf ) { + error( "Out of memory" ); return NULL; } @@ -612,11 +665,33 @@ unsigned char * cfb_getMiniSector( CFB_Data *cfbd, cfbSectorID_t id ) uint64_t offset = 0; uint32_t i = 0; - /* Fat Divisor: allow to guess the number of mini-stream sectors per standard sector */ + // debug( "Requesting fatID: %u (%u)", fatId, id ); + + /* Fat Divisor: allow to guess the number of mini-stream sectors per standard FAT sector */ unsigned int fatDiv = SectorSize / MiniSectorSize; /* move forward in the FAT's mini-stream chain to retrieve the sector we want. */ - for ( i = 0; i < id/fatDiv; i++ ) { fatId = cfbd->fat[fatId]; } + + for ( i = 0; i < id/fatDiv; i++ ) + { + if ( cfbd->fat[fatId] == 0 ) { + error( "Next FAT index (%i/%i) is null.", i, (id/fatDiv) ); + goto err; + } + + if ( cfbd->fat[fatId] >= CFB_MAX_REG_SID ) { + error( "Next FAT index (%i/%i) is invalid: %u (%08x)", i, (id/fatDiv), cfbd->fat[fatId], cfbd->fat[fatId] ); + goto err; + } + + if ( cfbd->fat[fatId] >= cfbd->fat_sz ) { + error( "Next FAT index (%i/%i) is bigger than FAT size (%u): %u (%08x)", i, (id/fatDiv), cfbd->fat_sz, cfbd->fat[fatId], cfbd->fat[fatId] ); + goto err; + } + + // debug( "sectorCount: %i / %u fatId: %u", i, id/fatDiv, cfbd->fat[fatId] ); + fatId = cfbd->fat[fatId]; + } offset = ((fatId + 1) << cfbd->hdr->_uSectorShift); offset += ((id % fatDiv ) << cfbd->hdr->_uMiniSectorShift); @@ -624,11 +699,17 @@ unsigned char * cfb_getMiniSector( CFB_Data *cfbd, cfbSectorID_t id ) if ( cfb_readFile( cfbd, buf, offset, MiniSectorSize ) == 0 ) { - free( buf ); - return NULL; + goto err; } + goto end; + +err: + free( buf ); + buf = NULL; + +end: return buf; } @@ -646,24 +727,21 @@ unsigned char * cfb_getMiniSector( CFB_Data *cfbd, cfbSectorID_t id ) uint64_t cfb_getStream( CFB_Data *cfbd, cfbNode *node, unsigned char **stream, uint64_t *stream_sz ) { + if ( node == NULL ) { + return 0; + } -// if ( node == NULL || node->_mse == STGTY_ROOT ) -// return; - -// Should not happen.. or could it ? -// if ( node->_ulSizeLow < 1 ) -// return; - uint64_t stream_len = cfb_getNodeStreamLen( cfbd, node ); //node->_ulSizeLow; + uint64_t stream_len = CFB_getNodeStreamLen( cfbd, node ); if ( stream_len == 0 ) { return 0; } - *stream = calloc( stream_len, sizeof(unsigned char) ); + *stream = calloc( 1, stream_len ); - if ( *stream == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !(*stream) ) { + error( "Out of memory" ); return 0; } @@ -675,7 +753,7 @@ uint64_t cfb_getStream( CFB_Data *cfbd, cfbNode *node, unsigned char **stream, u if ( stream_len < cfbd->hdr->_ulMiniSectorCutoff ) { /* mini-stream */ - cfb_foreachMiniSectorInChain( cfbd, buf, id ) { + CFB_foreachMiniSectorInChain( cfbd, buf, id ) { if ( !buf ) { free( *stream ); @@ -695,7 +773,7 @@ uint64_t cfb_getStream( CFB_Data *cfbd, cfbNode *node, unsigned char **stream, u } else { - cfb_foreachSectorInChain( cfbd, buf, id ) { + CFB_foreachSectorInChain( cfbd, buf, id ) { cpy_sz = ( (stream_len - offset) < (uint64_t)(1<hdr->_uSectorShift) ) ? (stream_len - offset) : (uint64_t)(1<hdr->_uSectorShift); @@ -720,7 +798,7 @@ uint64_t cfb_getStream( CFB_Data *cfbd, cfbNode *node, unsigned char **stream, u * Loops through all the sectors that compose a stream * and retrieve their content. * - * This function should be called through the macro cfb_foreachSectorInStream(). + * This function should be called through the macro CFB_foreachSectorInStream(). * * @param cfbd Pointer to the CFB_Data structure. * @param node Pointer to the Node that hold the stream. @@ -742,22 +820,17 @@ int cfb__foreachSectorInStream( CFB_Data *cfbd, cfbNode *node, unsigned char **b if ( *sectID >= CFB_MAX_REG_SID ) return 0; - /* is this possible ? */ -// if ( node->_ulSizeLow < 1 ) -// return 0; /* free the previously allocated buf, if any */ - if ( *buf != NULL ) { - free( *buf ); - *buf = NULL; - } + free( *buf ); + *buf = NULL; /* if *nodeID == 0, then it is the first function call */ *sectID = ( *sectID == 0 ) ? node->_sectStart : *sectID; - size_t stream_sz = cfb_getNodeStreamLen( cfbd, node ); + size_t stream_sz = CFB_getNodeStreamLen( cfbd, node ); if ( stream_sz < cfbd->hdr->_ulMiniSectorCutoff ) { /* Mini-Stream */ @@ -773,13 +846,6 @@ int cfb__foreachSectorInStream( CFB_Data *cfbd, cfbNode *node, unsigned char **b } - // trim data length to match the EXACT stream size - - // if ( *sectID >= CFB_MAX_REG_SECT ) - // *bytesRead = ( stream_sz % *bytesRead ); - // *bytesRead = ( stream_sz % *bytesRead ); - - return 1; } @@ -797,27 +863,38 @@ int cfb__foreachSectorInStream( CFB_Data *cfbd, cfbNode *node, unsigned char **b static int cfb_retrieveFileHeader( CFB_Data *cfbd ) { - cfbd->hdr = calloc( sizeof(cfbHeader), sizeof(unsigned char) ); + cfbd->hdr = calloc( 1, sizeof(cfbHeader) ); - if ( cfbd->hdr == NULL ) { - error( "%s.", strerror(errno) ); + if ( !cfbd->hdr ) { + error( "Out of memory" ); return -1; } if ( cfb_readFile( cfbd, (unsigned char*)cfbd->hdr, 0, sizeof(cfbHeader) ) == 0 ) { - free( cfbd->hdr ); - cfbd->hdr = NULL; - return -1; + goto err; + } + + if ( cfbd->hdr->_uSectorShift != 9 && + cfbd->hdr->_uSectorShift != 12 ) + { + goto err; } return 0; + +err: + free( cfbd->hdr ); + cfbd->hdr = NULL; + + return -1; } static int cfb_retrieveDiFAT( CFB_Data *cfbd ) { - cfbSectorID_t * DiFAT = NULL; + cfbSectorID_t *DiFAT = NULL; + unsigned char *buf = NULL; /* * Check DiFAT properties in header. @@ -827,13 +904,19 @@ static int cfb_retrieveDiFAT( CFB_Data *cfbd ) cfbSectorID_t csectDif = 0; if ( cfbd->hdr->_csectFat > 109 ) { - csectDif = ceil( (float)((cfbd->hdr->_csectFat - 109) * 4) / (1<hdr->_uSectorShift) ); + + double csectDifdouble = ceil( (float)((cfbd->hdr->_csectFat - 109) * 4) / (1<hdr->_uSectorShift) ); + + if ( csectDifdouble >= UINT_MAX || csectDifdouble < 0 ) { + warning( "Calculated csectDif is negative or bigger than UINT_MAX" ); + // return -1; + } + + csectDif = (cfbSectorID_t)csectDifdouble; } if ( csectDif != cfbd->hdr->_csectDif ) { - warning( "cfbd->hdr->_csectDif value seems wrong (%u)", cfbd->hdr->_csectDif ); - // warning( "cfbd->hdr->_csectDif value seems wrong (%u). Correcting from cfbd->hdr->_csectFat.", cfbd->hdr->_csectDif ); - // cfbd->hdr->_csectDif = csectDif; + warning( "cfbd->hdr->_csectDif value (%u) does not match calculated csectDif (%u)", cfbd->hdr->_csectDif, csectDif ); } if ( csectDif == 0 && cfbd->hdr->_sectDifStart != CFB_END_OF_CHAIN ) { @@ -844,17 +927,22 @@ static int cfb_retrieveDiFAT( CFB_Data *cfbd ) /* * DiFAT size is the number of FAT sector entries in the DiFAT chain. + * _uSectorShift is guaranted to be 9 or 12, so DiFAT_sz will never override UINT_MAX */ - uint32_t DiFAT_sz = ( cfbd->hdr->_csectDif ) + size_t DiFAT_sz = cfbd->hdr->_csectDif * (((1<hdr->_uSectorShift) / sizeof(cfbSectorID_t)) - 1) + 109; + if ( DiFAT_sz >= UINT_MAX ) { + error( "DiFAT size is bigger than UINT_MAX : %lu", DiFAT_sz ); + return -1; + } DiFAT = calloc( DiFAT_sz, sizeof(cfbSectorID_t) ); - if ( DiFAT == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !DiFAT ) { + error( "Out of memory" ); return -1; } @@ -867,24 +955,28 @@ static int cfb_retrieveDiFAT( CFB_Data *cfbd ) memcpy( DiFAT, cfbd->hdr->_sectFat, 109 * sizeof(cfbSectorID_t) ); - unsigned char *buf = NULL; - cfbSectorID_t id = 0; //cfbd->hdr->_sectDifStart; - uint64_t offset = 109 * sizeof(cfbSectorID_t); + cfbSectorID_t id = 0; + uint64_t offset = 109 * sizeof(cfbSectorID_t); uint64_t cnt = 0; - cfb_foreachSectorInDiFATChain( cfbd, buf, id ) { + /* _uSectorShift is guaranted to be 9 or 12, so sectorSize will never be negative */ + uint32_t sectorSize = (1U<hdr->_uSectorShift)-4U; + + + CFB_foreachSectorInDiFATChain( cfbd, buf, id ) { if ( buf == NULL ) { error( "Error retrieving sector %u (0x%08x) out of the DiFAT chain.", id, id ); - return -1; + goto err; } - memcpy( (unsigned char*)DiFAT+offset, buf, (1<hdr->_uSectorShift)-4 ); + memcpy( (unsigned char*)DiFAT+offset, buf, sectorSize ); - offset += (1 << cfbd->hdr->_uSectorShift) - 4; + offset += sectorSize; cnt++; + /* * If we count more DiFAT sector when parsing than * there should be, it means the sector list does @@ -896,6 +988,7 @@ static int cfb_retrieveDiFAT( CFB_Data *cfbd ) } free( buf ); + buf = NULL; /* * Standard says DIFAT should end with a CFB_END_OF_CHAIN index, @@ -906,9 +999,15 @@ static int cfb_retrieveDiFAT( CFB_Data *cfbd ) warning( "Incorrect end of DiFAT Chain 0x%08x (%d)", id, id ); cfbd->DiFAT = DiFAT; - cfbd->DiFAT_sz = DiFAT_sz; + cfbd->DiFAT_sz = (uint32_t)DiFAT_sz; return 0; + +err: + free( DiFAT ); + free( buf ); + + return -1; } @@ -925,14 +1024,14 @@ static int cfb_retrieveFAT( CFB_Data * cfbd ) { cfbSectorID_t *FAT = NULL; - uint64_t FAT_sz = (((cfbd->hdr->_csectFat) * (1<hdr->_uSectorShift))) + uint32_t FAT_sz = (((cfbd->hdr->_csectFat) * (1<hdr->_uSectorShift))) / sizeof(cfbSectorID_t); FAT = calloc( FAT_sz, sizeof(cfbSectorID_t) ); - if ( FAT == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !FAT ) { + error( "Out of memory" ); return -1; } @@ -945,11 +1044,13 @@ static int cfb_retrieveFAT( CFB_Data * cfbd ) cfbSectorID_t id = 0; uint64_t offset = 0; - cfb_foreachFATSectorIDInDiFAT( cfbd, id ) { + CFB_foreachFATSectorIDInDiFAT( cfbd, id ) { if ( cfbd->DiFAT[id] == CFB_FREE_SECT ) continue; + // debug( "cfbd->DiFAT[id]: %u", cfbd->DiFAT[id] ); + /* observed in fairlight's AAFs.. */ if ( cfbd->DiFAT[id] == 0x00000000 && id > 0 ) { warning( "Got a NULL FAT index in the DiFAT @ %u, should be CFB_FREE_SECT.", id ); @@ -958,6 +1059,8 @@ static int cfb_retrieveFAT( CFB_Data * cfbd ) buf = cfb_getSector( cfbd, cfbd->DiFAT[id] ); + // laaf_util_dump_hex( buf, (1<hdr->_uSectorShift), &cfbd->log->_msg, &cfbd->log->_msg_size, cfbd->log->_msg_pos, "" ); + if ( buf == NULL ) { error( "Error retrieving FAT sector %u (0x%08x).", id, id ); return -1; @@ -986,13 +1089,13 @@ static int cfb_retrieveFAT( CFB_Data * cfbd ) static int cfb_retrieveMiniFAT( CFB_Data * cfbd ) { - uint64_t miniFat_sz = cfbd->hdr->_csectMiniFat * (1<hdr->_uSectorShift) + uint32_t miniFat_sz = cfbd->hdr->_csectMiniFat * (1<hdr->_uSectorShift) / sizeof(cfbSectorID_t); cfbSectorID_t *miniFat = calloc( miniFat_sz, sizeof(cfbSectorID_t) ); - if ( miniFat == NULL ) { - error( "%s.", strerror(errno) ); + if ( !miniFat ) { + error( "Out of memory" ); return -1; } @@ -1001,7 +1104,7 @@ static int cfb_retrieveMiniFAT( CFB_Data * cfbd ) cfbSectorID_t id = cfbd->hdr->_sectMiniFatStart; uint64_t offset = 0; - cfb_foreachSectorInChain( cfbd, buf, id ) { + CFB_foreachSectorInChain( cfbd, buf, id ) { if ( buf == NULL ) { error( "Error retrieving MiniFAT sector %u (0x%08x).", id, id ); return -1; @@ -1050,8 +1153,8 @@ static int cfb_retrieveNodes( CFB_Data *cfbd ) cfbNode *node = calloc( cfbd->nodes_cnt, sizeof(cfbNode) ); - if ( node == NULL ) { - error( "%s.", strerror( errno ) ); + if ( !node ) { + error( "Out of memory" ); return -1; } @@ -1062,7 +1165,7 @@ static int cfb_retrieveNodes( CFB_Data *cfbd ) if ( cfbd->hdr->_uSectorShift == 9 ) { /* 512 bytes sectors */ - cfb_foreachSectorInChain( cfbd, buf, id ) { + CFB_foreachSectorInChain( cfbd, buf, id ) { if ( buf == NULL ) { error( "Error retrieving Directory sector %u (0x%08x).", id, id ); @@ -1079,7 +1182,7 @@ static int cfb_retrieveNodes( CFB_Data *cfbd ) } else if ( cfbd->hdr->_uSectorShift == 12 ) { /* 4096 bytes sectors */ - cfb_foreachSectorInChain( cfbd, buf, id ) { + CFB_foreachSectorInChain( cfbd, buf, id ) { if ( buf == NULL ) { error( "Error retrieving Directory sector %u (0x%08x).", id, id ); @@ -1127,10 +1230,13 @@ static int cfb_retrieveNodes( CFB_Data *cfbd ) /* handle non-standard sector size, that is different than 512B or 4kB */ /* TODO has not been tested yet, should not even exist anyway */ - warning( "Parsing non-standard sector size !!! (%u bytes)", (1<hdr->_uSectorShift) ) - uint32_t nodesPerSect = (1 << cfbd->hdr->_uMiniSectorShift) / sizeof(cfbNode); + warning( "Parsing non-standard sector size !!! (%u bytes)", (1<hdr->_uSectorShift) ); + + /* _uSectorShift is guaranted to be 9 or 12, so nodesPerSect will never override UINT_MAX */ + uint32_t nodesPerSect = (1U<hdr->_uMiniSectorShift) / sizeof(cfbNode); - cfb_foreachSectorInChain( cfbd, buf, id ) { + + CFB_foreachSectorInChain( cfbd, buf, id ) { if ( buf == NULL ) { error( "Error retrieving Directory sector %u (0x%08x).", id, id ); return -1; @@ -1153,41 +1259,24 @@ static int cfb_retrieveNodes( CFB_Data *cfbd ) /** - * Converts 16-bits MS/CFB wchar_t to system wchar_t. + * Converts UTF-16 to UTF-8. * - * @param buf Pointer to wchar_t output buffer. If NULL, then function will allocate a new buffer. - * @param w16buf Pointer to a 16-bits MS/CFB "wchar_t" array. - * @param w16blen Size of the w16buf array in bytes, including the NULL. If it is set to - * CFB_W16TOWCHAR_STRLEN, then function will parse w16buf up to NULL to retrieve w16buf byte size + * @param w16buf Pointer to a NULL terminated uint16_t UTF-16 array. + * @param w16blen Size of the w16buf array in bytes * - * @return Pointer to buf,\n + * @return New allocated buffer with UTF-8 string\n * NULL on failure. */ -wchar_t * cfb_w16towchar( wchar_t *buf, uint16_t *w16buf, size_t w16blen ) +char * cfb_w16toUTF8( const uint16_t *w16buf, size_t w16blen ) { - if ( w16buf == NULL ) - return NULL; - - if ( w16blen == CFB_W16TOWCHAR_STRLEN ) { - w16blen = 0; - while ( w16buf[w16blen>>1] != 0x0000 ) { - w16blen += sizeof(uint16_t); - } - w16blen += sizeof(uint16_t); /* NULL termination */ - } - - if ( buf == NULL ) { - buf = malloc( w16blen * sizeof(wchar_t) ); - if ( buf == NULL ) - return NULL; - } + (void)w16blen; - for ( size_t i = 0; i < w16blen>>1; i++ ) { - buf[i] = ((uint16_t*)w16buf)[i]; + if ( !w16buf ) { + return NULL; } - return buf; + return laaf_util_utf16Toutf8( w16buf ); } @@ -1204,7 +1293,7 @@ wchar_t * cfb_w16towchar( wchar_t *buf, uint16_t *w16buf, size_t w16blen ) * NULL on failure. */ -cfbNode * cfb_getNodeByPath( CFB_Data *cfbd, const wchar_t *path, cfbSID_t id ) +cfbNode * cfb_getNodeByPath( CFB_Data *cfbd, const char *path, cfbSID_t id ) { /* @@ -1221,21 +1310,29 @@ cfbNode * cfb_getNodeByPath( CFB_Data *cfbd, const wchar_t *path, cfbSID_t id ) * work either with or without "/Root Entry" */ - if ( wcsncmp( path, L"/Root Entry", 11 ) != 0 ) { + if ( strncmp( path, "/Root Entry", 11 ) != 0 ) { id = cfbd->nodes[0]._sidChild; } } - uint32_t l = 0; - /* * retrieves the first node's name from path */ - for( l = 0; l < wcslen(path); l++ ) - if ( l > 0 && path[l] == '/' ) + uint32_t nameLen = 0; + + for( nameLen = 0; nameLen < strlen(path); nameLen++ ) { + + if ( nameLen == UINT_MAX ) { + error( "Name length is bigger than UINT_MAX" ); + return NULL; + } + + if ( nameLen > 0 && path[nameLen] == '/' ) { break; + } + } /* * removes any leading '/' @@ -1243,11 +1340,18 @@ cfbNode * cfb_getNodeByPath( CFB_Data *cfbd, const wchar_t *path, cfbSID_t id ) if ( path[0] == '/' ) { path++; - l--; + nameLen--; } - wchar_t ab[CFB_NODE_NAME_SZ]; + size_t nameUTF16Len = (nameLen+1)<<1; + + if ( nameUTF16Len >= INT_MAX ) { + error( "Name length is bigger than INT_MAX" ); + return NULL; + } + + char *ab = NULL; while ( 1 ) { @@ -1256,16 +1360,17 @@ cfbNode * cfb_getNodeByPath( CFB_Data *cfbd, const wchar_t *path, cfbSID_t id ) return NULL; } - // laaf_util_dump_hex( cfbd->nodes[id]->_ab, cfbd->nodes[id]->_cb ); + ab = cfb_w16toUTF8( cfbd->nodes[id]._ab, cfbd->nodes[id]._cb ); - cfb_w16towchar( ab, cfbd->nodes[id]._ab, cfbd->nodes[id]._cb ); + int rc = 0; - int32_t rc = 0; + if ( strlen(ab) == nameLen ) + rc = strncmp( path, ab, nameLen ); + else { + rc = (int)nameUTF16Len - cfbd->nodes[id]._cb; + } - if ( wcslen(ab) == l ) - rc = wcsncmp( path, ab, l ); - else - rc = l - wcslen(ab); + free( ab ); /* * Some node in the path was found. @@ -1276,7 +1381,7 @@ cfbNode * cfb_getNodeByPath( CFB_Data *cfbd, const wchar_t *path, cfbSID_t id ) * get full path length minus any terminating '/' */ - uint32_t pathLen = wcslen(path); + size_t pathLen = strlen(path); if ( path[pathLen-1] == '/' ) pathLen--; @@ -1287,10 +1392,10 @@ cfbNode * cfb_getNodeByPath( CFB_Data *cfbd, const wchar_t *path, cfbSID_t id ) * to next node in the path. */ - if ( pathLen == l ) + if ( pathLen == nameLen ) return &cfbd->nodes[id]; else - return cfb_getNodeByPath( cfbd, path+l, cfbd->nodes[id]._sidChild ); + return cfb_getNodeByPath( cfbd, path+nameLen, cfbd->nodes[id]._sidChild ); } else if ( rc > 0 ) id = cfbd->nodes[id]._sidRightSib; else if ( rc < 0 ) id = cfbd->nodes[id]._sidLeftSib; @@ -1315,17 +1420,23 @@ cfbNode * cfb_getNodeByPath( CFB_Data *cfbd, const wchar_t *path, cfbSID_t id ) * NULL if not found. */ -cfbNode * cfb_getChildNode( CFB_Data *cfbd, const wchar_t *name, cfbNode *startNode ) +cfbNode * cfb_getChildNode( CFB_Data *cfbd, const char *name, cfbNode *startNode ) { + int rc = 0; - int32_t rc = 0; - - /** @TODO : cfb_getIDByNode should be quiker (macro ?) */ cfbSID_t id = cfb_getIDByNode( cfbd, &cfbd->nodes[startNode->_sidChild] ); - uint32_t nameUTF16Len = ((wcslen( name )+1) << 1); + if ( id == UINT_MAX ) { + error( "Could not retrieve id by node" ); + return NULL; + } - wchar_t nodename[CFB_NODE_NAME_SZ]; + size_t nameUTF16Len = ((strlen(name)+1) << 1); + + if ( nameUTF16Len >= INT_MAX ) { + error( "Name length is bigger than INT_MAX" ); + return NULL; + } while ( 1 ) { @@ -1334,13 +1445,15 @@ cfbNode * cfb_getChildNode( CFB_Data *cfbd, const wchar_t *name, cfbNode *startN return NULL; } - cfb_w16towchar( nodename, cfbd->nodes[id]._ab, cfbd->nodes[id]._cb ); + char *nodename = cfb_w16toUTF8( cfbd->nodes[id]._ab, cfbd->nodes[id]._cb ); if ( cfbd->nodes[id]._cb == nameUTF16Len ) - rc = wcscmp( name, nodename ); - else - rc = nameUTF16Len - cfbd->nodes[id]._cb; + rc = strcmp( name, nodename ); + else { + rc = (int)nameUTF16Len - cfbd->nodes[id]._cb; + } + free(nodename); /* * Node found */ @@ -1391,7 +1504,7 @@ static cfbSID_t cfb_getIDByNode( CFB_Data *cfbd, cfbNode *node ) } } - return -1; + return UINT_MAX; } @@ -1406,7 +1519,7 @@ static cfbSID_t cfb_getIDByNode( CFB_Data *cfbd, cfbNode *node ) static cfbSID_t getNodeCount( CFB_Data *cfbd ) { - uint64_t cnt = ( 1<hdr->_uSectorShift ); + uint32_t cnt = ( 1<hdr->_uSectorShift ); cfbSectorID_t id = cfbd->hdr->_sectDirStart; while ( id < CFB_MAX_REG_SID ) { diff --git a/src/common/log.c b/src/common/log.c new file mode 100644 index 0000000..b8c8383 --- /dev/null +++ b/src/common/log.c @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2017-2024 Adrien Gesta-Fline + * + * This file is part of libAAF. + * + * 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 + +#ifdef _WIN32 + #include + #include + #include +#endif + +#include +#include +#include +#include + +#include +#include + +/* + * swprintf() specific string format identifiers + * https://learn.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-170#size-prefixes-for-printf-and-wprintf-format-type-specifiers + */ + #ifdef __MINGW32__ + #define WPRIws L"ls" // wchar_t* + #define WPRIs L"s" // char* +#else + #define WPRIws L"ls" // wchar_t* + #define WPRIs L"S" // char* +#endif + + +struct aafLog * laaf_new_log( void ) +{ + struct aafLog *log = calloc( 1, sizeof(struct aafLog) ); + + if ( !log ) { + return NULL; + } + + log->debug_callback = &laaf_log_callback; + log->fp = stdout; + log->ansicolor = 0; + + return log; +} + + + +void laaf_free_log( struct aafLog *log ) +{ + if ( !log ) { + return; + } + + free( log->_msg ); + free( log ); +} + + + +void laaf_log_callback( struct aafLog *log, void *ctxdata, int libid, int type, const char *srcfile, const char *srcfunc, int lineno, const char *msg, void *user ) +{ + AAF_Iface *aafi = NULL; + AAF_Data *aafd = NULL; + CFB_Data *cfbd = NULL; + + const char *lib = ""; + const char *typestr = ""; + const char *color = ""; + + if ( log->fp == NULL ) { + DBG_BUFFER_RESET( log ); + return; + } + + switch ( libid ) { + case DEBUG_SRC_ID_LIB_CFB: lib = "libCFB"; aafi = (AAF_Iface*)ctxdata; break; + case DEBUG_SRC_ID_AAF_CORE: lib = "AAFCore"; aafd = (AAF_Data*)ctxdata; break; + case DEBUG_SRC_ID_AAF_IFACE: lib = "AAFIface"; cfbd = (CFB_Data*)ctxdata; break; + case DEBUG_SRC_ID_TRACE: lib = "trace"; aafi = (AAF_Iface*)ctxdata; break; + case DEBUG_SRC_ID_DUMP: lib = "dump"; break; + } + + switch ( type ) { + case VERB_SUCCESS: typestr = "success"; color = ANSI_COLOR_GREEN(log); break; + case VERB_ERROR: typestr = " error "; color = ANSI_COLOR_RED(log); break; + case VERB_WARNING: typestr = "warning"; color = ANSI_COLOR_YELLOW(log); break; + case VERB_DEBUG: typestr = " debug "; color = ANSI_COLOR_DARKGREY(log); break; + } + + const char *eol = ""; + + if ( libid != DEBUG_SRC_ID_TRACE && libid != DEBUG_SRC_ID_DUMP ) { +#ifdef __MINGW32__ + fwprintf( log->fp, L"[%"WPRIs"%"WPRIs"%"WPRIs"] %"WPRIs"%"WPRIs":%i in %"WPRIs"()%"WPRIs" : ", + color, + typestr, + ANSI_COLOR_RESET(log), + ANSI_COLOR_DARKGREY(log), + srcfile, + lineno, + srcfunc, + ANSI_COLOR_RESET(log) ); +#else + fprintf( log->fp, "[%s%s%s] %s%s:%i in %s()%s : ", + color, + typestr, + ANSI_COLOR_RESET(log), + ANSI_COLOR_DARKGREY(log), + srcfile, + lineno, + srcfunc, + ANSI_COLOR_RESET(log) ); +#endif + } + + if ( libid != DEBUG_SRC_ID_DUMP ) { + eol = "\n"; + } + +#ifdef __MINGW32__ + wchar_t *tmp = laaf_util_windows_utf8toutf16( msg ); + if ( !tmp ) { + return; + } + fwprintf( log->fp, L"%"WPRIws"%s", tmp, eol ); + free( tmp ); +#else + fprintf( log->fp, "%s%s", msg, eol ); +#endif + + fflush( log->fp ); + + DBG_BUFFER_RESET( log ); + + /* avoids -Wunused-parameter -Wunused-but-set-variable */ + (void)aafi; + (void)aafd; + (void)cfbd; + (void)lib; + (void)user; +} + + + +void laaf_write_log( struct aafLog *log, void *ctxdata, enum debug_source_id lib, enum verbosityLevel_e type, const char *dbgfile, const char *dbgfunc, int dbgline, const char *format, ... ) +{ + if ( !log ) { + return; + } + + if ( !log->debug_callback ) { + return; + } + + if ( type != VERB_SUCCESS && (log->verb == VERB_QUIET || type > log->verb) ) { + return; + } + + + va_list ap; + + int rc = 0; + size_t msgsize = 0; + + va_start( ap, format ); + +#ifdef _WIN32 + /* https://stackoverflow.com/a/4116308 */ + FILE *dummy = fopen( "NUL", "wb" ); + + if ( !dummy ) { + // fprintf( stderr, "Could not fopen() dummy null file\n" ); + return; + } + + rc = vfprintf( dummy, format, ap ); + + fclose( dummy ); + + if ( rc < 0 ) { + // fprintf( stderr, "vfwprintf() error : %s\n", strerror(errno) ); + va_end( ap ); + return; + } + + rc++; + rc *= (int)sizeof(wchar_t); + +#else + rc = vsnprintf( NULL, 0, format, ap ); + + if ( rc < 0 ) { + // fprintf( stderr, "vsnprintf() error : %s\n", strerror(errno) ); + va_end( ap ); + return; + } + + rc++; +#endif + + va_end( ap ); + + msgsize = (size_t)rc; + + + if ( log->_msg_pos ) { + log->_previous_pos = log->_msg_pos; + log->_previous_msg = laaf_util_c99strdup( log->_msg ); + if ( !log->_previous_msg ) { + // fprintf( stderr, "Out of memory\n" ); + return; + } + } + + + va_start( ap, format ); + + if ( msgsize >= log->_msg_size ) { + + char *msgtmp = realloc( log->_msg, (msgsize*sizeof(char)) ); + + if ( !msgtmp ) { + // fprintf( stderr, "Out of memory\n" ); + va_end( ap ); + return; + } + + log->_msg = msgtmp; + log->_msg_size = msgsize; + } + + rc = vsnprintf( log->_msg, log->_msg_size, format, ap ); + + if ( rc < 0 || (size_t)rc >= log->_msg_size ) { + // fprintf( stderr, "vsnprintf() error\n" ); + va_end( ap ); + return; + } + + log->debug_callback( log, (void*)ctxdata, lib, type, dbgfile, dbgfunc, dbgline, log->_msg, log->user ); + + va_end( ap ); + + + if ( log->_previous_pos ) { + log->_msg_pos = log->_previous_pos; + strcpy( log->_msg, log->_previous_msg ); + free( log->_previous_msg ); + log->_previous_msg = NULL; + log->_previous_pos = 0; + } +} diff --git a/src/common/utils.c b/src/common/utils.c index 346e9f9..49aeb53 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2023 Adrien Gesta-Fline + * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * @@ -23,106 +23,103 @@ #include #include #include +#include +#include #include +#if defined(__linux__) + #include + #include + #include + #include /* access() */ +#elif defined(__APPLE__) + #include + #include /* access() */ +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) + #include + #define R_OK 4 /* Test for read permission. */ + #define W_OK 2 /* Test for write permission. */ + #define F_OK 0 /* Test for existence. */ + #ifndef _MSC_VER + #include // access() + #endif +#endif + #include #define BUILD_PATH_DEFAULT_BUF_SIZE 1024 +static int utf8CodeLen( const uint16_t *u16Code ); +static int utf16CodeLen( const uint16_t *u16Code ); +static int utf16CodeToUTF8( const uint16_t *u16Code, char *u8Code, int *u16Len, int *u8Len ); +static long utf8strLen( const uint16_t *u16str ); -aafPosition_t laaf_util_converUnit( aafPosition_t value, aafRational_t *valueEditRate, aafRational_t *destEditRate ) { - if ( !valueEditRate || !destEditRate ) { - return value; - } - if ( valueEditRate->numerator == destEditRate->numerator && - valueEditRate->denominator == destEditRate->denominator ) - { - /* same rate, no conversion */ - return value; - } +#ifdef _WIN32 - double valueEditRateFloat = (( valueEditRate->denominator == 0 ) ? 0.0 : ((float)valueEditRate->numerator / valueEditRate->denominator)); - double destEditRateFloat = (( destEditRate->denominator == 0 ) ? 0.0 : ((float)destEditRate->numerator / destEditRate->denominator )); +wchar_t * laaf_util_windows_utf8toutf16( const char *str ) { - if ( valueEditRateFloat == 0 ) { - return 0; + if ( !str ) { + return NULL; } - return value * (destEditRateFloat / valueEditRateFloat); -} - - + int needed = MultiByteToWideChar( CP_UTF8, 0, str, -1, NULL, 0 ); -char * laaf_util_wstr2str( const wchar_t *wstr ) { - - if ( wstr == NULL ) { + if ( needed == 0 ) { return NULL; } - size_t strsz = wcslen( wstr ) + 1; - char *str = malloc( strsz ); + wchar_t *wbuf = malloc( (size_t)needed * sizeof(wchar_t) ); - if ( str == NULL ) { - // error( "Could not allocate memory : %s", strerror(errno) ); + if ( !wbuf ) { return NULL; } - int rc = snprintf( str, strsz, "%ls", wstr ); + int rc = MultiByteToWideChar( CP_UTF8, 0, str, -1, wbuf, needed ); - if ( rc < 0 || (unsigned)rc >= strsz ) { - // error( "Failed converting wide char str to byte char str%s", (reqlen < 0) ? " : encoding error" : "" ); - free( str ); + if ( rc == 0 ) { + free( wbuf ); return NULL; } - return str; + return wbuf; } -wchar_t * laaf_util_str2wstr( const char *str ) { +char * laaf_util_windows_utf16toutf8( const wchar_t *wstr ) { - if ( str == NULL ) { + if ( !wstr ) { return NULL; } - size_t strsz = strlen( str ) + 1; - wchar_t *wstr = malloc( strsz * sizeof(wchar_t) ); + int needed = WideCharToMultiByte( CP_UTF8, 0, wstr, -1, NULL, 0, 0, 0 ); - if ( str == NULL ) { - // error( "Could not allocate memory : %s", strerror(errno) ); + if ( needed == 0 ) { return NULL; } - int rc = swprintf( wstr, strsz, L"%" WPRIs, str ); + char *buf = malloc( (size_t)needed * sizeof(char) ); - if ( rc < 0 || (unsigned)rc >= strsz ) { - // error( "Failed converting byte char str to wide char str%s", (reqlen < 0) ? " : encoding error" : "" ); - free( wstr ); + if ( !buf ) { return NULL; } - return wstr; -} - + int rc = WideCharToMultiByte( CP_UTF8, 0, wstr, -1, buf, needed, 0, 0 ); - -int laaf_util_wstr_contains_nonlatin( const wchar_t *str ) -{ - for ( size_t i = 0; str[i] != 0x0000; i++ ) { - /* if char is out of the Basic Latin range */ - if ( str[i] > 0xff ) { - return 1; - } + if ( rc == 0 ) { + free( buf ); + return NULL; } - return 0; + return buf; } +#endif + char * laaf_util_clean_filename( char *fname ) @@ -131,85 +128,67 @@ char * laaf_util_clean_filename( char *fname ) * sanitize file/dir name * https://stackoverflow.com/a/31976060 */ - size_t len = strlen(fname); - - for ( size_t i = 0; i < len; i++ ) { - - unsigned char c = fname[i]; - - if ( c == '/' || - c == '<' || - c == '>' || - c == ':' || - c == '"' || - c == '|' || - c == '?' || - c == '*' || - c == '\\' || - (c > 0 && c < 0x20) ) - { - fname[i] = '_'; - } + if ( !fname ) { + return NULL; } - /* windows filenames can't end with ' ' or '.' */ - for ( int i = len-1; i > 0; i-- ) { - char c = fname[i]; - if ( c != ' ' && c != '.' ) { - break; + char *p = fname; + + while ( *p ) { + if ( *p == '/' || + *p == '<' || + *p == '>' || + *p == ':' || + *p == '"' || + *p == '|' || + *p == '?' || + *p == '*' || + *p == '\\' || + (*p > 0 && *p < 0x20) ) + { + *p = '_'; } - fname[i] = '_'; + p++; } - return fname; -} - + /* windows filenames can't end with ' ' or '.' */ + p = fname + strlen(fname)-1; -const char * laaf_util_fop_get_file( const char *filepath ) -{ - if ( filepath == NULL ) { - return NULL; + while ( *p && (*p == ' ' || *p == '.') ) { + *p = '\0'; p--; } - const char *end = filepath + strlen(filepath); - - while ( end > filepath && !IS_DIR_SEP(*end) ) { - --end; - } + if ( *fname == '\0' ) + return NULL; - return ( IS_DIR_SEP(*end) ) ? end+1 : end; + return fname; } -int laaf_util_fop_is_wstr_fileext( const wchar_t *filepath, const wchar_t *ext ) +int laaf_util_is_fileext( const char *filepath, const char *ext ) { - if ( filepath == NULL ) { + if ( !filepath || !ext ) { return 0; } - const wchar_t *end = filepath + wcslen(filepath); + const char *end = filepath + strlen(filepath); size_t extlen = 0; while ( end > filepath && (*end) != '.' ) { - --end; - extlen++; + --end; extlen++; } if ( (*end) == '.' ) { - end++; - extlen--; + end++; extlen--; } - if ( extlen != wcslen(ext) ) { + if ( !extlen || extlen != strlen(ext) ) { return 0; } - // printf(" end: %ls ext: %ls\n", end, ext ); - - for (size_t i = 0; i < extlen; i++) { - // printf("end: %c != %c\n", *(end+i), *(ext+i)); + for ( size_t i = 0; i < extlen; i++ ) { if ( tolower( *(end+i) ) != tolower( *(ext+i) ) ) { return 0; } @@ -224,7 +203,7 @@ char * laaf_util_build_path( const char *sep, const char *first, ... ) { char *str = malloc( BUILD_PATH_DEFAULT_BUF_SIZE ); - if ( str == NULL ) { + if ( !str ) { return NULL; } @@ -245,14 +224,13 @@ char * laaf_util_build_path( const char *sep, const char *first, ... ) const char *arg = first; do { - - int arglen = strlen(arg); - int argstart = 0; + size_t arglen = strlen(arg); + size_t argstart = 0; int has_leading_sep = 0; /* trim leading DIR_SEP */ for ( int i = 0; arg[i] != 0x00; i++ ) { - if ( IS_DIR_SEP(arg[i]) ) { + if ( IS_ANY_DIR_SEP(arg[i]) ) { has_leading_sep = 1; argstart++; } else { @@ -261,74 +239,235 @@ char * laaf_util_build_path( const char *sep, const char *first, ... ) } /* trim trailing DIR_SEP */ - for ( int i = arglen-1; i >= argstart; i-- ) { - if ( IS_DIR_SEP(arg[i]) ) { + for ( size_t i = arglen-1; i >= argstart; i-- ) { + if ( IS_ANY_DIR_SEP(arg[i]) ) { arglen--; } else { break; } } - /* TODO ? */ - if ( element_count == 0 && has_leading_sep ) { - } - else { - } - - size_t reqlen = snprintf( NULL, 0, "%.*s", arglen-argstart, arg+argstart ) + 1; + size_t reqlen = (arglen-argstart) + 2; if ( offset + reqlen >= len ) { - reqlen = ((offset + reqlen) > (len + BUILD_PATH_DEFAULT_BUF_SIZE)) ? (offset + reqlen) : (len + BUILD_PATH_DEFAULT_BUF_SIZE); + reqlen = ((offset + reqlen) > (len + BUILD_PATH_DEFAULT_BUF_SIZE)) ? (reqlen) : (len + BUILD_PATH_DEFAULT_BUF_SIZE); char *tmp = realloc( str, (offset + reqlen) ); - if ( tmp ) { - str = tmp; - len = (offset + reqlen); - } else { + if ( !tmp ) { free( str ); return NULL; } + + str = tmp; + len = (offset + reqlen); } - offset += snprintf( str + offset, len - offset, "%s%.*s", + int written = snprintf( str + offset, len - offset, "%s%.*s", ( (element_count == 0 && has_leading_sep) || (element_count > 0) ) ? sep : "", - arglen-argstart, + (uint32_t)(arglen-argstart), arg+argstart ); + if ( written < 0 || (size_t)written >= (len - offset) ) { + free( str ); + return NULL; + } + + offset += (size_t)written; + element_count++; } while ( (arg = va_arg(args, char*)) != NULL ); va_end( args ); + /* do not mix between different dirseps and removes any consecutive dirseps */ + char *i = str; + char *o = str; + int dirseppassed = 0; + while ( *i ) { + if ( !dirseppassed && IS_ANY_DIR_SEP(*i) ) { + *o = *sep; + o++; + dirseppassed = 1; + } + else if ( !IS_ANY_DIR_SEP(*i) ) { + dirseppassed = 0; + *o = *i; + o++; + } + i++; + } + *o = '\0'; + return str; } -int laaf_util_snprintf_realloc( char **str, int *size, size_t offset, const char *format, ... ) +char * laaf_util_relative_path( const char *filepath, const char *refpath ) { - int tmpsize = 0; + if ( !filepath || !refpath || filepath[0] == '\0' || refpath[0] == '\0' ) { + return NULL; + } + + // fprintf( stderr, "%s\n", filepath ); + // fprintf( stderr, "%s\n", refpath ); + + int isWindowsPath = 0; + int aWindowsPath = 0; + int bWindowsPath = 0; + + char *relpath = NULL; + + if ( filepath[0] != '\0' && isalpha(filepath[0]) && filepath[1] == ':' ) { + aWindowsPath = 1; + } + + if ( refpath[0] != '\0' && isalpha(refpath[0]) && refpath[1] == ':' ) { + bWindowsPath = 1; + } + + isWindowsPath = (aWindowsPath + bWindowsPath); + + if ( isWindowsPath == 1 ) { + // fprintf( stderr, "Trying to make a relative path out of a windows path and a non-windows path\n" ); + return NULL; + } + + if ( isWindowsPath == 2 ) { + if ( tolower(filepath[0]) != tolower(refpath[0]) ) { + // fprintf( stderr, "Both paths target different drives\n" ); + return NULL; + } + } + + int winDriveLetterOffset = isWindowsPath; + + if ( strncmp( filepath+winDriveLetterOffset, refpath+winDriveLetterOffset, strlen(refpath) ) == 0 ) { + relpath = laaf_util_build_path( "/", "./", filepath + strlen(refpath), NULL ); + return relpath; + } + + char *_filepath = laaf_util_build_path( "/", filepath, NULL ); + char *_refpath = laaf_util_build_path( "/", refpath, "/", NULL ); /* ensures there is always a trailing '/' */ + + if ( !_filepath || !_refpath ) { + return NULL; + } + + char *parents = NULL; + size_t parentsLen = 0; + size_t parentsOffset = 0; + + char *p = _refpath + strlen(_refpath); + + while ( p > (_refpath+winDriveLetterOffset) ) { + + while ( p > (_refpath+winDriveLetterOffset) && !IS_DIR_SEP(*p) ) { + *p = '\0'; + p--; + } + + if ( strncmp( _filepath+winDriveLetterOffset, _refpath+winDriveLetterOffset, strlen(_refpath+winDriveLetterOffset) ) == 0 ) { + if ( !parents ) { + relpath = laaf_util_build_path( "/", "./", _filepath + strlen(_refpath), NULL ); + goto end; + } + else { + relpath = laaf_util_build_path( "/", parents, _filepath + strlen(_refpath), NULL ); + goto end; + } + } + + int ret = laaf_util_snprintf_realloc( &parents, &parentsLen, parentsOffset, "../" ); + + assert( ret >= 0 ); + + parentsOffset += (size_t)ret; + p--; + } + +end: + free( parents ); + free( _filepath ); + free( _refpath ); + + return relpath; +} + + + +char * laaf_util_absolute_path( const char *relpath ) +{ + if ( !relpath ) { + return NULL; + } + +#ifdef _WIN32 + // char *abspath = NULL; + wchar_t buf[_MAX_PATH]; + + wchar_t *wrelpath = laaf_util_windows_utf8toutf16( relpath ); + + if ( !wrelpath ) { + return NULL; + } + + if ( !_wfullpath( buf, wrelpath, _MAX_PATH ) ) { + free( wrelpath ); + return NULL; + } + + char *abspath = laaf_util_windows_utf16toutf8( buf ); + + if ( !abspath ) { + free( wrelpath ); + return NULL; + } + + free( wrelpath ); + + return abspath; + +#else + char buf[PATH_MAX+1]; + + if ( !realpath( relpath, buf ) ) { + return NULL; + } + + return laaf_util_c99strdup( buf ); + +#endif +} + + + +int laaf_util_snprintf_realloc( char **str, size_t *size, size_t offset, const char *format, ... ) +{ + size_t tmpsize = 0; if ( !size ) { size = &tmpsize; } - int retval, needed; + int retval = 0; + size_t needed = 0; va_list ap; + va_start(ap, format); while ( 0 <= (retval = vsnprintf( (*str)+offset, (*size)-offset, format, ap) ) - && (int64_t)((*size)-offset) < (needed = retval + 1) ) + && ((*size)-offset) < (needed = (unsigned)retval + 1) ) { va_end( ap ); *size *= 2; - if ( (int64_t)((*size)-offset) < needed ) + if ( ((*size)-offset) < needed ) *size = needed + offset; char *p = realloc( *str, *size ); @@ -340,7 +479,7 @@ int laaf_util_snprintf_realloc( char **str, int *size, size_t offset, const char free( *str ); *str = NULL; *size = 0; - return -1; + return 0; } va_start( ap, format ); @@ -348,41 +487,281 @@ int laaf_util_snprintf_realloc( char **str, int *size, size_t offset, const char va_end( ap ); - return retval; + return ( retval > 0 ) ? retval : 0; } -int laaf_util_vsnprintf_realloc( char **str, int *size, int offset, const char *fmt, va_list *args ) +int laaf_util_file_exists( const char *filepath ) { - va_list args2, args3; +#ifdef _WIN32 + int needed = MultiByteToWideChar( CP_UTF8, 0, filepath, -1, NULL, 0 ); - va_copy( args2, *args ); - va_copy( args3, *args ); + if ( needed == 0 ) { + return -1; + } + + wchar_t *wfilepath = malloc( (size_t)needed * sizeof(wchar_t) ); + + if ( !wfilepath ) { + return -1; + } - int needed = vsnprintf( NULL, 0, fmt, args2 ) + 1; + int rc = MultiByteToWideChar( CP_UTF8, 0, filepath, -1, wfilepath, needed ); + + if ( rc == 0 ) { + free( wfilepath ); + return -1; + } + + if ( _waccess( wfilepath, F_OK ) == 0 ) { + free( wfilepath ); + return 1; + } + + free( wfilepath ); + +#else + if ( access( filepath, F_OK ) == 0 ) { + return 1; + } +#endif + + return 0; +} + + + +static int utf8CodeLen( const uint16_t *u16Code ) +{ + if ( u16Code[0] < 0x80 ) { + return 1; + } + else if ( u16Code[0] < 0x800 ) { + return 2; + } + else if ( u16Code[0] < 0xD800 || + u16Code[0] > 0xDFFF ) { + return 3; + } + else if ((( u16Code[0] & 0xFC00) == 0xD800 ) && + (( u16Code[1] & 0xFC00) == 0xDC00 )) + { + return 4; + } + else { + return -1; + } +} + + + +static int utf16CodeLen( const uint16_t *u16Code ) +{ + if ( u16Code[0] < 0xD800 || + u16Code[0] > 0xDFFF ) + { + return 1; + } + else if ( ((u16Code[0] & 0xFC00) == 0xD800) && + ((u16Code[1] & 0xFC00) == 0xDC00) ) + { + return 2; + } + else { + return -1; + } +} + + + +static int utf16CodeToUTF8( const uint16_t *u16Code, char *u8Code, int *u16Len, int *u8Len ) +{ + int len8 = utf8CodeLen(u16Code); + int len16 = utf16CodeLen(u16Code); + + if ( len8 < 0 || len16 < 0 ) { + return -1; + } + + *u8Len = len8; + *u16Len = len16; + + if ( len8 == 1 ) { + u8Code[0] = (char)(u16Code[0]); + } + else if ( len8 == 2 ) { + u8Code[0] = (char)(0xC0 | (u16Code[0] >> 6)); + u8Code[1] = (char)(0x80 | (u16Code[0] & 0x3F)); + } + else if ( len8 == 3 ) { + u8Code[0] = (char)(0xE0 | (u16Code[0] >> 12)); + u8Code[1] = (char)(0x80 | ((u16Code[0] >> 6) & 0x3F)); + u8Code[2] = (char)(0x80 | (u16Code[0] & 0x3F)); + } + else { + uint32_t c = (u16Code[0] & 0x03FF) << 10; + + c |= (u16Code[1] & 0x03FF); + c += 0x10000; + + u8Code[0] = (char)(0xF0 | ((c >> 18) & 0x07)); + u8Code[1] = (char)(0x80 | ((c >> 12) & 0x3F)); + u8Code[2] = (char)(0x80 | ((c >> 6) & 0x3F)); + u8Code[3] = (char)(0x80 | (c & 0x3F)); + } + + return *u8Len; +} + + + +static long utf8strLen( const uint16_t *u16str ) +{ + long len = 0; + const uint16_t *p = u16str; + + while ( *p != 0x0000 ) { + + int u8CodeLen = utf8CodeLen(p); + int u16CodeLen = utf16CodeLen(p); + + if ( u8CodeLen < 0 || u16CodeLen < 0 ) { + len = -1; + break; + } + + p += u16CodeLen; + len += u8CodeLen; + } + + return len; +} + + + +size_t laaf_util_utf8strCharLen( const char *u8str ) +{ + size_t count = 0; + + while (*u8str) { + count += (*u8str++ & 0xC0) != 0x80; + } + + return count; +} + + + +char * laaf_util_utf16Toutf8( const uint16_t *u16str ) +{ + long u8len = utf8strLen(u16str); + + if ( u8len < 0 ) { + return 0; + } + + char *u8str = calloc( (size_t)u8len+1, sizeof(char) ); + + if ( !u8str ) { + return NULL; + } + + const uint16_t *u16ptr = u16str; + char *u8ptr = u8str; + + while ( *u16ptr != 0x0000 ) { + + int u8codelen = 0; + int u16codelen = 0; + + utf16CodeToUTF8( u16ptr, u8ptr, &u16codelen, &u8codelen ); + + if ( u16codelen < 0 || u8codelen < 0 ) { + free( u8str ); + return NULL; + } + + u8ptr += u8codelen; + u16ptr += u16codelen; + } + + *u8ptr = 0x00; + + return u8str; +} + + + +int laaf_util_vsnprintf_realloc( char **str, size_t *size, size_t offset, const char *fmt, va_list args ) +{ + FILE *dummy = NULL; + va_list args1; + + size_t tmpsize = 0; + + if ( size == NULL ) { + size = &tmpsize; + } + + va_copy( args1, args ); + + + /* https://stackoverflow.com/a/4116308 */ +#ifndef _WIN32 + dummy = fopen( "/dev/null", "wb" ); +#else + dummy = fopen( "NUL", "wb" ); +#endif + + if ( !dummy ) { + // fprintf( stderr, "Could not fopen() dummy null file\n" ); + goto err; + } + + int retval = vfprintf( dummy, fmt, args ); + + if ( retval < 0 ) { + // fprintf( stderr, "vfprintf() error : %s\n", strerror(errno) ); + goto err; + } + + unsigned needed = (unsigned)retval + 1; if ( needed >= (*size) - offset ) { - char *p = realloc( *str, offset+needed ); + char *p = realloc( *str, (offset+needed) * sizeof(char) ); if ( p ) { *str = p; *size = offset+needed; } else { - /* If realloc() fails, the original block is left untouched; it is not freed or moved. */ - va_end( args2 ); - va_end( args3 ); - - return -1; + goto err; } } - va_end( args2 ); - int written = vsnprintf( (*str)+offset, (*size)-offset, fmt, args3 ); - va_end( args3 ); + int written = vsnprintf( (*str)+offset, (*size)-offset, fmt, args1 ); + + // assert( written >= 0 && (size_t)written < (*size)-offset ); + + if ( written < 0 && (size_t)written >= (*size)-offset ) { + fprintf( stderr, "vsnprintf() error : %s\n", strerror(errno) ); + goto err; + } + + goto end; + + +err: + written = -1; + +end: + + if ( dummy ) { + fclose( dummy ); + } return written; } @@ -395,7 +774,7 @@ char * laaf_util_c99strdup( const char *src ) return NULL; } - int len = 0; + size_t len = 0; while ( src[len] ) { len++; @@ -403,8 +782,9 @@ char * laaf_util_c99strdup( const char *src ) char *str = malloc( len + 1 ); - if ( !str ) + if ( !str ) { return NULL; + } char *p = str; @@ -419,25 +799,32 @@ char * laaf_util_c99strdup( const char *src ) -int laaf_util_dump_hex( const unsigned char *stream, size_t stream_sz, char **buf, int *bufsz, int offset ) +int laaf_util_dump_hex( const unsigned char *stream, size_t stream_sz, char **buf, size_t *bufsz, size_t offset, const char *padding ) { if ( stream == NULL ) { return -1; } - int initialOffset = offset; + size_t initialOffset = offset; uint32_t i = 0; char hex[49]; char ascii[19]; - uint32_t count = 0; + size_t count = 0; + + int rc = laaf_util_snprintf_realloc( buf, bufsz, offset, "%s______________________________ Hex Dump ______________________________\n\n", padding ); + + if ( rc < 0 ) { + goto end; + } + + offset += (size_t)rc; - offset += laaf_util_snprintf_realloc( buf, bufsz, offset, " ______________________________ Hex Dump ______________________________\n\n" ); while ( count < stream_sz ) { - uint32_t lineLen = (stream_sz - count) / 16; + size_t lineLen = (stream_sz - count) / 16; if ( lineLen <= 0 ) lineLen = (stream_sz) % 16; @@ -452,21 +839,27 @@ int laaf_util_dump_hex( const unsigned char *stream, size_t stream_sz, char **bu for ( i=0; i < lineLen; i++ ) { - linepos += snprintf( &hex[linepos], sizeof(hex)-(linepos), "%02x%s", *(const unsigned char*)(stream+count+i), (i==7) ? " " : " " ); + rc = snprintf( &hex[linepos], sizeof(hex)-(linepos), "%02x%s", *(const unsigned char*)(stream+count+i), (i==7) ? " " : " " ); + + if ( rc < 0 ) { + goto end; + } + + linepos += (uint32_t)rc; if ( i < 8 ) { - if ( isalnum( *(stream+count+i) ) ) ascii[i] = *(const unsigned char*)(stream+count+i); - else ascii[i] = '.'; + if ( isalnum( *(stream+count+i) ) ) ascii[i] = *(const char*)(stream+count+i); + else ascii[i] = '.'; } else if ( i > 8 ) { - if ( isalnum( *(stream+count+i) ) ) ascii[i+1] = *(const unsigned char*)(stream+count+i); - else ascii[i+1] = '.'; + if ( isalnum( *(stream+count+i) ) ) ascii[i+1] = *(const char*)(stream+count+i); + else ascii[i+1] = '.'; } else { if ( isalnum( *(stream+count+i) ) ) { ascii[i] = ' '; - ascii[i+1] = *(const unsigned char*)(stream+count+i); + ascii[i+1] = *(const char*)(stream+count+i); } else { ascii[i] = ' '; @@ -487,10 +880,21 @@ int laaf_util_dump_hex( const unsigned char *stream, size_t stream_sz, char **bu count += lineLen; - offset += laaf_util_snprintf_realloc( buf, bufsz, offset, " %s | %s\n", hex, ascii ); + rc = laaf_util_snprintf_realloc( buf, bufsz, offset, "%s%s | %s\n", padding, hex, ascii ); + + if ( rc < 0 ) { + goto end; + } + + offset += (size_t)rc; } - offset += laaf_util_snprintf_realloc( buf, bufsz, offset, " ______________________________________________________________________\n\n" ); + rc = laaf_util_snprintf_realloc( buf, bufsz, offset, "%s______________________________________________________________________\n\n", padding ); + + if ( rc < 0 ) { + goto end; + } - return offset - initialOffset; /* bytes written */ +end: + return (int)(offset - initialOffset); /* bytes written */ } diff --git a/src/debug.c b/src/debug.c deleted file mode 100644 index f6076bc..0000000 --- a/src/debug.c +++ /dev/null @@ -1,81 +0,0 @@ -#include - -#include - -#include -#include -#include -#include - -#include - - -struct dbg * laaf_new_debug( void ) -{ - struct dbg *dbg = calloc( sizeof(struct dbg), sizeof(char) ); - - dbg->debug_callback = &laaf_debug_callback; - dbg->fp = stdout; - dbg->ansicolor = 0; - - return dbg; -} - - - -void laaf_free_debug( struct dbg *dbg ) -{ - if ( dbg->_dbg_msg ) { - free( dbg->_dbg_msg ); - } - - free( dbg ); -} - - - -void laaf_debug_callback( struct dbg *dbg, void *ctxdata, int libid, int type, const char *srcfile, const char *srcfunc, int lineno, const char *msg, void *user ) -{ - AAF_Iface *aafi = NULL; - AAF_Data *aafd = NULL; - CFB_Data *cfbd = NULL; - - const char *lib = ""; - const char *typestr = ""; - const char *color = ""; - - if ( dbg->fp == NULL ) { - DBG_BUFFER_RESET( dbg ); - return; - } - - switch ( libid ) { - case DEBUG_SRC_ID_LIB_CFB: lib = "libCFB"; aafi = (AAF_Iface*)ctxdata; break; - case DEBUG_SRC_ID_AAF_CORE: lib = "AAFCore"; aafd = (AAF_Data*)ctxdata; break; - case DEBUG_SRC_ID_AAF_IFACE: lib = "AAFIface"; cfbd = (CFB_Data*)ctxdata; break; - case DEBUG_SRC_ID_TRACE: lib = "trace"; aafi = (AAF_Iface*)ctxdata; break; - case DEBUG_SRC_ID_DUMP: lib = "dump"; break; - } - - switch ( type ) { - case VERB_ERROR: typestr = " error "; color = ANSI_COLOR_RED(dbg); break; - case VERB_WARNING: typestr = "warning"; color = ANSI_COLOR_YELLOW(dbg); break; - case VERB_DEBUG: typestr = " debug "; color = ANSI_COLOR_DARKGREY(dbg); break; - } - - if ( libid != DEBUG_SRC_ID_TRACE && libid != DEBUG_SRC_ID_DUMP ) { - fprintf( dbg->fp, "[%s%s%s] ", color, typestr, ANSI_COLOR_RESET(dbg) ); - fprintf( dbg->fp, "%s%s:%i in %s()%s : ", ANSI_COLOR_DARKGREY(dbg), srcfile, lineno, srcfunc, ANSI_COLOR_RESET(dbg) ); - } - - fprintf( dbg->fp, "%s\n", msg ); - - DBG_BUFFER_RESET( dbg ); - - /* avoids -Wunused-parameter -Wunused-but-set-variable */ - (void)aafi; - (void)aafd; - (void)cfbd; - (void)lib; - (void)user; -} diff --git a/src/index.md b/src/index.md deleted file mode 100644 index 90a2bec..0000000 --- a/src/index.md +++ /dev/null @@ -1,29 +0,0 @@ -# LibAAF {#mainpage} - -LibAAF is a C coded library for parsing **Advanced Authoring File Format**. It is released under the **GNU AGPLv3**. - -The AAF specification can be found at https://www.amwa.tv/developers.shtml - -LibAAF source code can be downloaded at https://github.com/agfline/LibAAF - -LibAAF is composed of 3 parts : **LibCFB**, **AAFCore** and **AAFIface**. - ---- - -## LibCFB - -The LibCFB is a library written on this occasion, to access the low-level structure of the AAF. - -The AAF is actualy built upon the Microsoft's *Compound File Binary File Format* (a.k.a *Structured Storage File Format*), which is closely related to the FAT file system, with its FAT table, Sectors and all. The LibCFB should only be accessed by the AAFCore, there's no need for the user to directly talk to it. - -The specifications of the low-level structure can be found at https://www.amwa.tv/projects/MS-03.shtml - -## AAFCore - -Then like in any file system, we have access to a tree of nodes (directories and files), starting with the **Root Entry** node. Each directory is an Object representing an AAF Class. Each directory has a file called **properties** that holds the members of the Class. A Class can inherit other Classes members. - -Some special file nodes named with the suffix **index** hold either a StrongReferenceSet or a StrongReferenceVector. Those are lists of references to other nodes name with the same prefix and with the suffix ***{n}***, ***n*** being an index number. The prefix of the name is hold by a Class member. The only difference between Sets and Vectors is that Set Objects are unordered but can be referenced by an unique ID, while Vectors Objects are ordered and can only be referenced by their index number. - - - - diff --git a/test/README.md b/test/README.md index 624ccc3..491a91f 100644 --- a/test/README.md +++ b/test/README.md @@ -50,7 +50,6 @@ - [ ] Mono clip + track volume automation - [x] Mono clip gain + clip volume automation - [x] Stereo clip gain + clip volume automation - - [ ] Mono clip pan automation - [ ] Stereo clip pan automation - [ ] Mono track pan automation diff --git a/test/aaf/DR_Audio_Levels.aaf b/test/aaf/DR_Audio_Levels.aaf new file mode 100755 index 0000000..f7d3b18 Binary files /dev/null and b/test/aaf/DR_Audio_Levels.aaf differ diff --git a/test/aaf/MC_Audio_Levels.aaf b/test/aaf/MC_Audio_Levels.aaf new file mode 100755 index 0000000..a6dc023 Binary files /dev/null and b/test/aaf/MC_Audio_Levels.aaf differ diff --git a/test/aaf/MC_Audio_Pan.aaf b/test/aaf/MC_Audio_Pan.aaf new file mode 100755 index 0000000..703570e Binary files /dev/null and b/test/aaf/MC_Audio_Pan.aaf differ diff --git a/test/aaf/MC_Audio_Warp.aaf b/test/aaf/MC_Audio_Warp.aaf new file mode 100755 index 0000000..6591d61 Binary files /dev/null and b/test/aaf/MC_Audio_Warp.aaf differ diff --git a/test/aaf/MC_Clip_Mute.aaf b/test/aaf/MC_Clip_Mute.aaf new file mode 100755 index 0000000..2fe2aa0 Binary files /dev/null and b/test/aaf/MC_Clip_Mute.aaf differ diff --git a/test/aaf/MC_Empty.aaf b/test/aaf/MC_Empty.aaf new file mode 100755 index 0000000..db16f25 Binary files /dev/null and b/test/aaf/MC_Empty.aaf differ diff --git a/test/aaf/MC_Fades.aaf b/test/aaf/MC_Fades.aaf new file mode 100755 index 0000000..cf5cd56 Binary files /dev/null and b/test/aaf/MC_Fades.aaf differ diff --git a/test/aaf/MC_Markers.aaf b/test/aaf/MC_Markers.aaf new file mode 100755 index 0000000..4c6cceb Binary files /dev/null and b/test/aaf/MC_Markers.aaf differ diff --git a/test/aaf/MC_Metadata.aaf b/test/aaf/MC_Metadata.aaf new file mode 100755 index 0000000..f3a54f4 Binary files /dev/null and b/test/aaf/MC_Metadata.aaf differ diff --git a/test/aaf/MC_TC_100.aaf b/test/aaf/MC_TC_100.aaf new file mode 100755 index 0000000..d4a49d6 Binary files /dev/null and b/test/aaf/MC_TC_100.aaf differ diff --git a/test/aaf/MC_TC_119.88_DF.aaf b/test/aaf/MC_TC_119.88_DF.aaf new file mode 100755 index 0000000..fd65fe0 Binary files /dev/null and b/test/aaf/MC_TC_119.88_DF.aaf differ diff --git a/test/aaf/MC_TC_119.88_NDF.aaf b/test/aaf/MC_TC_119.88_NDF.aaf new file mode 100755 index 0000000..42806d1 Binary files /dev/null and b/test/aaf/MC_TC_119.88_NDF.aaf differ diff --git a/test/aaf/MC_TC_120_DF.aaf b/test/aaf/MC_TC_120_DF.aaf new file mode 100755 index 0000000..08cc782 Binary files /dev/null and b/test/aaf/MC_TC_120_DF.aaf differ diff --git a/test/aaf/MC_TC_120_NDF.aaf b/test/aaf/MC_TC_120_NDF.aaf new file mode 100755 index 0000000..39632c1 Binary files /dev/null and b/test/aaf/MC_TC_120_NDF.aaf differ diff --git a/test/aaf/MC_TC_23.976.aaf b/test/aaf/MC_TC_23.976.aaf new file mode 100755 index 0000000..d87ebda Binary files /dev/null and b/test/aaf/MC_TC_23.976.aaf differ diff --git a/test/aaf/MC_TC_24.aaf b/test/aaf/MC_TC_24.aaf new file mode 100755 index 0000000..552f79d Binary files /dev/null and b/test/aaf/MC_TC_24.aaf differ diff --git a/test/aaf/MC_TC_25.aaf b/test/aaf/MC_TC_25.aaf new file mode 100755 index 0000000..369b0e0 Binary files /dev/null and b/test/aaf/MC_TC_25.aaf differ diff --git a/test/aaf/MC_TC_29.97_DF.aaf b/test/aaf/MC_TC_29.97_DF.aaf new file mode 100755 index 0000000..1dbe712 Binary files /dev/null and b/test/aaf/MC_TC_29.97_DF.aaf differ diff --git a/test/aaf/MC_TC_29.97_NDF.aaf b/test/aaf/MC_TC_29.97_NDF.aaf new file mode 100755 index 0000000..ae2d353 Binary files /dev/null and b/test/aaf/MC_TC_29.97_NDF.aaf differ diff --git a/test/aaf/MC_TC_30_DF.aaf b/test/aaf/MC_TC_30_DF.aaf new file mode 100755 index 0000000..a3ce1e5 Binary files /dev/null and b/test/aaf/MC_TC_30_DF.aaf differ diff --git a/test/aaf/MC_TC_30_NDF.aaf b/test/aaf/MC_TC_30_NDF.aaf new file mode 100755 index 0000000..7e400cd Binary files /dev/null and b/test/aaf/MC_TC_30_NDF.aaf differ diff --git a/test/aaf/MC_TC_50.aaf b/test/aaf/MC_TC_50.aaf new file mode 100755 index 0000000..d86e9d6 Binary files /dev/null and b/test/aaf/MC_TC_50.aaf differ diff --git a/test/aaf/MC_TC_59.94_DF.aaf b/test/aaf/MC_TC_59.94_DF.aaf new file mode 100755 index 0000000..610eb06 Binary files /dev/null and b/test/aaf/MC_TC_59.94_DF.aaf differ diff --git a/test/aaf/MC_TC_59.94_NDF.aaf b/test/aaf/MC_TC_59.94_NDF.aaf new file mode 100755 index 0000000..213fbb4 Binary files /dev/null and b/test/aaf/MC_TC_59.94_NDF.aaf differ diff --git a/test/aaf/MC_TC_60_DF.aaf b/test/aaf/MC_TC_60_DF.aaf new file mode 100755 index 0000000..f497755 Binary files /dev/null and b/test/aaf/MC_TC_60_DF.aaf differ diff --git a/test/aaf/MC_TC_60_NDF.aaf b/test/aaf/MC_TC_60_NDF.aaf new file mode 100755 index 0000000..60d15b6 Binary files /dev/null and b/test/aaf/MC_TC_60_NDF.aaf differ diff --git a/test/aaf/MC_Track_Solo_Mute.aaf b/test/aaf/MC_Track_Solo_Mute.aaf new file mode 100755 index 0000000..8d9b088 Binary files /dev/null and b/test/aaf/MC_Track_Solo_Mute.aaf differ diff --git a/test/aaf/PR_Audio_Levels-noBTM.aaf b/test/aaf/PR_Audio_Levels-noBTM.aaf new file mode 100644 index 0000000..a23196b Binary files /dev/null and b/test/aaf/PR_Audio_Levels-noBTM.aaf differ diff --git a/test/aaf/PR_Audio_Pan-noBTM.aaf b/test/aaf/PR_Audio_Pan-noBTM.aaf new file mode 100644 index 0000000..c0e24dc Binary files /dev/null and b/test/aaf/PR_Audio_Pan-noBTM.aaf differ diff --git a/test/aaf/PT_Audio_Levels-noEMCC-noExpTracksAsMultiChannel.aaf b/test/aaf/PT_Audio_Levels-noEMCC-noExpTracksAsMultiChannel.aaf new file mode 100755 index 0000000..9d26cfd Binary files /dev/null and b/test/aaf/PT_Audio_Levels-noEMCC-noExpTracksAsMultiChannel.aaf differ diff --git a/test/aaf/PT_Fades.aaf b/test/aaf/PT_Fades.aaf new file mode 100755 index 0000000..f1230a6 Binary files /dev/null and b/test/aaf/PT_Fades.aaf differ diff --git a/test/aaf/PT_Fades_A.aaf b/test/aaf/PT_Fades_A.aaf new file mode 100755 index 0000000..f1230a6 Binary files /dev/null and b/test/aaf/PT_Fades_A.aaf differ diff --git a/test/aaf/PT_Fades_B.aaf b/test/aaf/PT_Fades_B.aaf new file mode 100755 index 0000000..f1230a6 Binary files /dev/null and b/test/aaf/PT_Fades_B.aaf differ diff --git a/test/aaf/PT_Fades_no_handles.aaf b/test/aaf/PT_Fades_no_handles.aaf new file mode 100755 index 0000000..4fd9a59 Binary files /dev/null and b/test/aaf/PT_Fades_no_handles.aaf differ diff --git a/test/aaf/PT_UTF8_EssencePath.aaf b/test/aaf/PT_UTF8_EssencePath.aaf new file mode 100755 index 0000000..050f8e3 Binary files /dev/null and b/test/aaf/PT_UTF8_EssencePath.aaf differ diff --git a/test/aaf/PT_lang_de.aaf b/test/aaf/PT_lang_de.aaf new file mode 100755 index 0000000..26c6157 Binary files /dev/null and b/test/aaf/PT_lang_de.aaf differ diff --git a/test/aaf/PT_lang_en.aaf b/test/aaf/PT_lang_en.aaf new file mode 100755 index 0000000..63c6c18 Binary files /dev/null and b/test/aaf/PT_lang_en.aaf differ diff --git a/test/aaf/PT_lang_es.aaf b/test/aaf/PT_lang_es.aaf new file mode 100755 index 0000000..ef0d90f Binary files /dev/null and b/test/aaf/PT_lang_es.aaf differ diff --git a/test/aaf/PT_lang_fr.aaf b/test/aaf/PT_lang_fr.aaf new file mode 100755 index 0000000..59bfa19 Binary files /dev/null and b/test/aaf/PT_lang_fr.aaf differ diff --git a/test/aaf/PT_lang_ja.aaf b/test/aaf/PT_lang_ja.aaf new file mode 100755 index 0000000..806a8d0 Binary files /dev/null and b/test/aaf/PT_lang_ja.aaf differ diff --git a/test/aaf/PT_lang_ko.aaf b/test/aaf/PT_lang_ko.aaf new file mode 100755 index 0000000..f4b1c55 Binary files /dev/null and b/test/aaf/PT_lang_ko.aaf differ diff --git a/test/aaf/PT_lang_zh_CN.aaf b/test/aaf/PT_lang_zh_CN.aaf new file mode 100755 index 0000000..e00b802 Binary files /dev/null and b/test/aaf/PT_lang_zh_CN.aaf differ diff --git a/test/aaf/PT_lang_zh_TW.aaf b/test/aaf/PT_lang_zh_TW.aaf new file mode 100755 index 0000000..4ef84b1 Binary files /dev/null and b/test/aaf/PT_lang_zh_TW.aaf differ diff --git "a/test/aaf/\330\247\331\204\331\201\331\210\330\266\331\211/PT_UTF8_EsszxcxBYZCdpbxHBBB.wav" "b/test/aaf/\330\247\331\204\331\201\331\210\330\266\331\211/PT_UTF8_EsszxcxBYZCdpbxHBBB.wav" new file mode 100755 index 0000000..39f2f3c Binary files /dev/null and "b/test/aaf/\330\247\331\204\331\201\331\210\330\266\331\211/PT_UTF8_EsszxcxBYZCdpbxHBBB.wav" differ diff --git a/test/expected/DR_Audio_Levels.aaf.expected b/test/expected/DR_Audio_Levels.aaf.expected new file mode 100644 index 0000000..5bfff5c --- /dev/null +++ b/test/expected/DR_Audio_Levels.aaf.expected @@ -0,0 +1,264 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-10 11:31:23.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Blackmagic Design + ProductName : DaVinci Resolve + ProductVersion : 18.5.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0x64a8d1aa 0x7ffd 0x0000 { 0x01 0x00 0x87 0x01 0x00 0x00 0x00 0x00 } } + Date : 2024-01-10 11:31:23.00 + ToolkitVersion : 1.1.6.0 AAFVersionReleased (1) + Platform : AAFSDK (Win32) + GenerationAUID : { 0x48f08870 0x3cf0 0x4aba { 0xb0 0x65 0x9f 0x76 0x82 0x2e 0x7b 0x41 } } + + + + Composition Name : DR_Audio_Levels + + TC EditRrate : 24/1 + TC FPS : 24 NDF + + Composition Start (EU) : 86400 + Composition Start (samples) : 79380000 + Composition Start : 01:00:00:00 + + Composition End (EU) : 89352 (EditRate: 24/1) + Composition End (samples) : 82092150 + Composition End : 01:02:03:00 + + Dominant Sample Rate : 22050 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "stereo-identif" UniqueName: "stereo-identif_7" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + + Audio[2] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "stereo-identif" UniqueName: "stereo-identif_6" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + + Audio[3] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "stereo-identif" UniqueName: "stereo-identif_5" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + + Audio[4] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "stereo-identif" UniqueName: "stereo-identif_4" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + + Audio[5] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "stereo-identif" UniqueName: "stereo-identif_3" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + + Audio[6] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "stereo-identif" UniqueName: "stereo-identif_2" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + + Audio[7] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "stereo-identif" UniqueName: "stereo-identif_1" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + + Audio[8] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "stereo-identif" UniqueName: "stereo-identif" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + + Audio[9] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 132300 Name: "1000hz-18dbs16b44" UniqueName: "1000hz-18dbs16b44_3" + └── File: "file://localhost/C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.wav" + + Audio[10] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 132300 Name: "1000hz-18dbs16b44" UniqueName: "1000hz-18dbs16b44_2" + └── File: "file://localhost/C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.wav" + + Audio[11] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 132300 Name: "1000hz-18dbs16b44" UniqueName: "1000hz-18dbs16b44_1" + └── File: "file://localhost/C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.wav" + + Audio[12] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 132300 Name: "1000hz-18dbs16b44" UniqueName: "1000hz-18dbs16b44" + └── File: "file://localhost/C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 24/1 (24.00) + + + AudioTrack[1] :: EditRate: 24/1 (24.00) Format: MONO Name: "Audio 1" + ├── Clip (1): Start: 80041500 Len: 66150 End: 80107650 SourceOffset: 0 Channels: 1 Gain: -99.0 dB + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44" + │ + ├── Clip (2): Start: 80703000 Len: 66150 End: 80769150 SourceOffset: 0 Channels: 1 Gain: +06.0 dB + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44_1" + │ + ├── Clip (3): Start: 81364500 Len: 66150 End: 81430650 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "1000hz-18dbs16b44_2" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 0.013889 _value: 1.000000 (+00.0 dB) + │ _time: 0.027778 _value: 0.966051 (-00.3 dB) + │ _time: 0.041667 _value: 0.668344 (-03.5 dB) + │ _time: 0.055556 _value: 0.384592 (-08.3 dB) + │ _time: 0.069444 _value: 0.102329 (-19.8 dB) + │ _time: 0.083333 _value: 0.000207 (-73.7 dB) + │ _time: 0.263889 _value: 0.000011 (-99.0 dB) + │ _time: 0.277778 _value: 0.000136 (-77.3 dB) + │ _time: 0.291667 _value: 0.005188 (-45.7 dB) + │ _time: 0.305556 _value: 0.014622 (-36.7 dB) + │ _time: 0.319444 _value: 0.086099 (-21.3 dB) + │ _time: 0.333333 _value: 0.151356 (-16.4 dB) + │ _time: 0.347222 _value: 0.354813 (-09.0 dB) + │ _time: 0.361111 _value: 0.473151 (-06.5 dB) + │ _time: 0.375000 _value: 0.741310 (-02.6 dB) + │ _time: 0.388889 _value: 1.174898 (+01.4 dB) + │ _time: 0.402778 _value: 1.445440 (+03.2 dB) + │ _time: 0.416667 _value: 1.883649 (+05.5 dB) + │ _time: 0.430556 _value: 3.162278 (+10.0 dB) + │ _time: 0.527778 _value: 3.162278 (+10.0 dB) + │ _time: 0.541667 _value: 2.691535 (+08.6 dB) + │ _time: 0.555556 _value: 1.778279 (+05.0 dB) + │ _time: 0.569444 _value: 1.303167 (+02.3 dB) + │ _time: 0.583333 _value: 1.083927 (+00.7 dB) + │ _time: 0.597222 _value: 0.851138 (-01.4 dB) + │ _time: 0.611111 _value: 0.707946 (-03.0 dB) + │ _time: 0.625000 _value: 0.668344 (-03.5 dB) + │ _time: 0.638889 _value: 0.623735 (-04.1 dB) + │ _time: 0.652778 _value: 0.602560 (-04.4 dB) + │ _time: 0.666667 _value: 0.543250 (-05.3 dB) + │ _time: 0.680556 _value: 0.501187 (-06.0 dB) + │ _time: 0.694444 _value: 0.451856 (-06.9 dB) + │ _time: 0.708333 _value: 0.375837 (-08.5 dB) + │ _time: 0.722222 _value: 0.354813 (-09.0 dB) + │ _time: 0.763889 _value: 0.334965 (-09.5 dB) + │ _time: 0.777778 _value: 0.375837 (-08.5 dB) + │ _time: 0.902778 _value: 0.375837 (-08.5 dB) + │ _time: 0.916667 _value: 0.384592 (-08.3 dB) + │ _time: 0.930556 _value: 0.384592 (-08.3 dB) + │ _time: 0.944444 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ + └── Clip (4): Start: 82026000 Len: 66150 End: 82092150 SourceOffset: 0 Channels: 1 Gain: +03.0 dB VolumeAutomation: YES + ├── SourceFile [ch 1]: "1000hz-18dbs16b44_3" + └── Clip Volume Automation ────────────────────── + _time: 0.000000 _value: 1.000000 (+00.0 dB) + _time: 0.013889 _value: 1.000000 (+00.0 dB) + _time: 0.027778 _value: 0.966051 (-00.3 dB) + _time: 0.041667 _value: 0.668344 (-03.5 dB) + _time: 0.055556 _value: 0.384592 (-08.3 dB) + _time: 0.069444 _value: 0.102329 (-19.8 dB) + _time: 0.083333 _value: 0.000207 (-73.7 dB) + _time: 0.263889 _value: 0.000011 (-99.0 dB) + _time: 0.277778 _value: 0.000136 (-77.3 dB) + _time: 0.291667 _value: 0.005188 (-45.7 dB) + _time: 0.305556 _value: 0.014622 (-36.7 dB) + _time: 0.319444 _value: 0.086099 (-21.3 dB) + _time: 0.333333 _value: 0.151356 (-16.4 dB) + _time: 0.347222 _value: 0.354813 (-09.0 dB) + _time: 0.361111 _value: 0.473151 (-06.5 dB) + _time: 0.375000 _value: 0.741310 (-02.6 dB) + _time: 0.388889 _value: 1.174898 (+01.4 dB) + _time: 0.402778 _value: 1.445440 (+03.2 dB) + _time: 0.416667 _value: 1.883649 (+05.5 dB) + _time: 0.430556 _value: 3.162278 (+10.0 dB) + _time: 0.527778 _value: 3.162278 (+10.0 dB) + _time: 0.541667 _value: 2.691535 (+08.6 dB) + _time: 0.555556 _value: 1.778279 (+05.0 dB) + _time: 0.569444 _value: 1.303167 (+02.3 dB) + _time: 0.583333 _value: 1.083927 (+00.7 dB) + _time: 0.597222 _value: 0.851138 (-01.4 dB) + _time: 0.611111 _value: 0.707946 (-03.0 dB) + _time: 0.625000 _value: 0.668344 (-03.5 dB) + _time: 0.638889 _value: 0.623735 (-04.1 dB) + _time: 0.652778 _value: 0.602560 (-04.4 dB) + _time: 0.666667 _value: 0.543250 (-05.3 dB) + _time: 0.680556 _value: 0.501187 (-06.0 dB) + _time: 0.694444 _value: 0.451856 (-06.9 dB) + _time: 0.708333 _value: 0.375837 (-08.5 dB) + _time: 0.722222 _value: 0.354813 (-09.0 dB) + _time: 0.763889 _value: 0.334965 (-09.5 dB) + _time: 0.777778 _value: 0.375837 (-08.5 dB) + _time: 0.902778 _value: 0.375837 (-08.5 dB) + _time: 0.916667 _value: 0.384592 (-08.3 dB) + _time: 0.930556 _value: 0.384592 (-08.3 dB) + _time: 0.944444 _value: 1.000000 (+00.0 dB) + _time: 1.000000 _value: 1.000000 (+00.0 dB) + + + AudioTrack[2] :: EditRate: 24/1 (24.00) Format: STEREO Name: "Audio 2" + ├── Clip (1): Start: 80041500 Len: 42262 End: 80083762 SourceOffset: 0 Channels: 2 Gain: -99.0 dB + │ ├── SourceFile [ch 1]: "stereo-identif" + │ └── SourceFile [ch 2]: "stereo-identif_1" + │ + ├── Clip (2): Start: 80703000 Len: 42262 End: 80745262 SourceOffset: 0 Channels: 2 Gain: +06.0 dB + │ ├── SourceFile [ch 1]: "stereo-identif_2" + │ └── SourceFile [ch 2]: "stereo-identif_3" + │ + ├── Clip (3): Start: 81364500 Len: 42262 End: 81406762 SourceOffset: 0 Channels: 2 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "stereo-identif_4" + │ ├── SourceFile [ch 2]: "stereo-identif_5" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 0.130435 _value: 1.000000 (+00.0 dB) + │ _time: 0.152174 _value: 0.966051 (-00.3 dB) + │ _time: 0.173913 _value: 0.803526 (-01.9 dB) + │ _time: 0.195652 _value: 0.426580 (-07.4 dB) + │ _time: 0.217391 _value: 0.260016 (-11.7 dB) + │ _time: 0.239130 _value: 0.118850 (-18.5 dB) + │ _time: 0.260870 _value: 0.024547 (-32.2 dB) + │ _time: 0.282609 _value: 0.000741 (-62.6 dB) + │ _time: 0.304348 _value: 0.000011 (-99.0 dB) + │ _time: 0.434783 _value: 0.000011 (-99.0 dB) + │ _time: 0.456522 _value: 0.000207 (-73.7 dB) + │ _time: 0.478261 _value: 0.002512 (-52.0 dB) + │ _time: 0.500000 _value: 0.009661 (-40.3 dB) + │ _time: 0.521739 _value: 0.030200 (-30.4 dB) + │ _time: 0.543478 _value: 0.102329 (-19.8 dB) + │ _time: 0.565217 _value: 0.167880 (-15.5 dB) + │ _time: 0.586957 _value: 0.327341 (-09.7 dB) + │ _time: 0.608696 _value: 0.384592 (-08.3 dB) + │ _time: 0.630435 _value: 0.501187 (-06.0 dB) + │ _time: 0.652174 _value: 0.588844 (-04.6 dB) + │ _time: 0.673913 _value: 0.683912 (-03.3 dB) + │ _time: 0.695652 _value: 0.803526 (-01.9 dB) + │ _time: 0.717391 _value: 0.912011 (-00.8 dB) + │ _time: 0.739130 _value: 1.000000 (+00.0 dB) + │ _time: 0.782609 _value: 1.059254 (+00.5 dB) + │ _time: 0.804348 _value: 1.083927 (+00.7 dB) + │ _time: 0.826087 _value: 1.109175 (+00.9 dB) + │ _time: 0.847826 _value: 1.174898 (+01.4 dB) + │ _time: 1.000000 _value: 1.174898 (+01.4 dB) + │ + └── Clip (4): Start: 82026000 Len: 42262 End: 82068262 SourceOffset: 0 Channels: 2 Gain: +03.0 dB VolumeAutomation: YES + ├── SourceFile [ch 1]: "stereo-identif_6" + ├── SourceFile [ch 2]: "stereo-identif_7" + └── Clip Volume Automation ────────────────────── + _time: 0.000000 _value: 1.000000 (+00.0 dB) + _time: 0.130435 _value: 1.000000 (+00.0 dB) + _time: 0.152174 _value: 0.966051 (-00.3 dB) + _time: 0.173913 _value: 0.803526 (-01.9 dB) + _time: 0.195652 _value: 0.426580 (-07.4 dB) + _time: 0.217391 _value: 0.260016 (-11.7 dB) + _time: 0.239130 _value: 0.118850 (-18.5 dB) + _time: 0.260870 _value: 0.024547 (-32.2 dB) + _time: 0.282609 _value: 0.000741 (-62.6 dB) + _time: 0.304348 _value: 0.000011 (-99.0 dB) + _time: 0.434783 _value: 0.000011 (-99.0 dB) + _time: 0.456522 _value: 0.000207 (-73.7 dB) + _time: 0.478261 _value: 0.002512 (-52.0 dB) + _time: 0.500000 _value: 0.009661 (-40.3 dB) + _time: 0.521739 _value: 0.030200 (-30.4 dB) + _time: 0.543478 _value: 0.102329 (-19.8 dB) + _time: 0.565217 _value: 0.167880 (-15.5 dB) + _time: 0.586957 _value: 0.327341 (-09.7 dB) + _time: 0.608696 _value: 0.384592 (-08.3 dB) + _time: 0.630435 _value: 0.501187 (-06.0 dB) + _time: 0.652174 _value: 0.588844 (-04.6 dB) + _time: 0.673913 _value: 0.683912 (-03.3 dB) + _time: 0.695652 _value: 0.803526 (-01.9 dB) + _time: 0.717391 _value: 0.912011 (-00.8 dB) + _time: 0.739130 _value: 1.000000 (+00.0 dB) + _time: 0.782609 _value: 1.059254 (+00.5 dB) + _time: 0.804348 _value: 1.083927 (+00.7 dB) + _time: 0.826087 _value: 1.109175 (+00.9 dB) + _time: 0.847826 _value: 1.174898 (+01.4 dB) + _time: 1.000000 _value: 1.174898 (+01.4 dB) + + diff --git a/test/expected/DR_Empty.aaf.expected b/test/expected/DR_Empty.aaf.expected index d167e05..d637de0 100644 --- a/test/expected/DR_Empty.aaf.expected +++ b/test/expected/DR_Empty.aaf.expected @@ -40,13 +40,11 @@ Media Essences : ================ - Tracks & Clips : ================ -VideoTrack (1) - edit_rate 24/1 (24.00) - "" -Track (1) - Unknwn - Gain: none - Pan: none - edit_rate: 24/1 (24.00) - "Audio 1" - + VideoTrack[1] :: EditRate: 24/1 (24.00) + AudioTrack[1] :: EditRate: 24/1 (24.00) Format: Unknwn Name: "Audio 1" diff --git a/test/expected/DR_MP3_External.aaf.expected b/test/expected/DR_MP3_External.aaf.expected index 908d307..f3c64da 100644 --- a/test/expected/DR_MP3_External.aaf.expected +++ b/test/expected/DR_MP3_External.aaf.expected @@ -39,17 +39,18 @@ Media Essences : ================ - 0: Type: PCM Length: 144000 01 Ch - 48000 Hz - 16 bits file: file:///C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz.mp3 file_name: 1000hz + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 144000 Name: "1000hz" UniqueName: "1000hz" + └── File: "file:///C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz.mp3" Tracks & Clips : ================ -VideoTrack (1) - edit_rate 24/1 (24.00) - "" -Track (1) - MONO - Gain: none - Pan: none - edit_rate: 24/1 (24.00) - "Audio 1" - Clip:0 Channel: 1 Gain: none GainAuto: none Start: 172800000 Len: 144000 End: 172944000 SrcOffset: 0 - SourceFile: [ch 1] 1000hz (1000hz) - + VideoTrack[1] :: EditRate: 24/1 (24.00) + AudioTrack[1] :: EditRate: 24/1 (24.00) Format: MONO Name: "Audio 1" + └── Clip (1): Start: 172800000 Len: 144000 End: 172944000 SourceOffset: 0 Channels: 1 + └── SourceFile [ch 1]: "1000hz" + diff --git a/test/expected/DR_Markers.aaf.expected b/test/expected/DR_Markers.aaf.expected index e25288c..bb9c1eb 100644 --- a/test/expected/DR_Markers.aaf.expected +++ b/test/expected/DR_Markers.aaf.expected @@ -40,15 +40,14 @@ Media Essences : ================ - Tracks & Clips : ================ -VideoTrack (1) - edit_rate 24/1 (24.00) - "" -Markers : -========= + VideoTrack[1] :: EditRate: 24/1 (24.00) - Marker[0]: EditRate: 24/1 Start: 0 Length: 0 Color: #e12401 Label: "Marker1Name" Comment: "This is a maker note. Marker is at position 01:01:00:00, last 1 frame and its color is red." - Marker[1]: EditRate: 24/1 Start: 0 Length: 0 Color: #9013fe Label: "Marker2Name" Comment: "This is a maker note. Marker is at position 01:01:30:00, last 10 frames and its color is purple." +Markers : +========= + Marker[0]: EditRate: 24/1 (24.00) Start: 0 Length: 0 Color: #e12401 Label: "Marker1Name" Comment: "This is a maker note. Marker is at position 01:01:00:00, last 1 frame and its color is red." + Marker[1]: EditRate: 24/1 (24.00) Start: 0 Length: 0 Color: #9013fe Label: "Marker2Name" Comment: "This is a maker note. Marker is at position 01:01:30:00, last 10 frames and its color is purple." diff --git a/test/expected/DR_Mono_Clip_Positioning.aaf.expected b/test/expected/DR_Mono_Clip_Positioning.aaf.expected index 6daafe6..7b58f04 100644 --- a/test/expected/DR_Mono_Clip_Positioning.aaf.expected +++ b/test/expected/DR_Mono_Clip_Positioning.aaf.expected @@ -39,26 +39,36 @@ Media Essences : ================ - 0: Type: WAVE Length: 132300 01 Ch - 44100 Hz - 16 bits file: file://localhost/C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.wav file_name: sample-accuracy-173459321 - 1: Type: WAVE Length: 132300 01 Ch - 44100 Hz - 16 bits file: file://localhost/C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.wav file_name: tc-accurate-01:00:09:00-173232000 - 2: Type: WAVE Length: 132300 01 Ch - 44100 Hz - 16 bits file: file://localhost/C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.wav file_name: sample-accurate-173000000 - 3: Type: WAVE Length: 132300 01 Ch - 44100 Hz - 16 bits file: file://localhost/C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.wav file_name: 1000hz-18dbs16b44 + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 132300 Name: "sample-accuracy-173459321" UniqueName: "sample-accuracy-173459321" + └── File: "file://localhost/C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.wav" + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 132300 Name: "tc-accurate-01:00:09:00-173232000" UniqueName: "tc-accurate-01:00:09:00-173232000" + └── File: "file://localhost/C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.wav" -Tracks & Clips : -================ + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 132300 Name: "sample-accurate-173000000" UniqueName: "sample-accurate-173000000" + └── File: "file://localhost/C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.wav" -VideoTrack (1) - edit_rate 24/1 (24.00) - "" -Track (1) - MONO - Gain: none - Pan: none - edit_rate: 48000/1 (48000.00) - "Audio 1" - Clip:0 Channel: 1 Gain: none GainAuto: none Start: 158760000 Len: 132300 End: 158892300 SrcOffset: 0 - SourceFile: [ch 1] 1000hz-18dbs16b44 (1000hz-18dbs16b44) - Clip:1 Channel: 1 Gain: none GainAuto: none Start: 158943750 Len: 132300 End: 159076050 SrcOffset: 0 - SourceFile: [ch 1] sample-accurate-173000000 (sample-accurate-173000000) - Clip:2 Channel: 1 Gain: none GainAuto: none Start: 159156900 Len: 132300 End: 159289200 SrcOffset: 0 - SourceFile: [ch 1] tc-accurate-01:00:09:00-173232000 (tc-accurate-01:00:09:00-173232000) - Clip:3 Channel: 1 Gain: none GainAuto: none Start: 159365751 Len: 132300 End: 159498051 SrcOffset: 0 - SourceFile: [ch 1] sample-accuracy-173459321 (sample-accuracy-173459321) + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 132300 Name: "1000hz-18dbs16b44" UniqueName: "1000hz-18dbs16b44" + └── File: "file://localhost/C:/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.wav" +Tracks & Clips : +================ + VideoTrack[1] :: EditRate: 24/1 (24.00) + + + AudioTrack[1] :: EditRate: 48000/1 (48000.00) Format: MONO Name: "Audio 1" + ├── Clip (1): Start: 158760000 Len: 132300 End: 158892300 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44" + │ + ├── Clip (2): Start: 158943750 Len: 132300 End: 159076050 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "sample-accurate-173000000" + │ + ├── Clip (3): Start: 159156900 Len: 132300 End: 159289200 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "tc-accurate-01:00:09:00-173232000" + │ + └── Clip (4): Start: 159365751 Len: 132300 End: 159498051 SourceOffset: 0 Channels: 1 + └── SourceFile [ch 1]: "sample-accuracy-173459321" + diff --git a/test/expected/DR_Multichannel_5.1_single_source.aaf.expected b/test/expected/DR_Multichannel_5.1_single_source.aaf.expected index c33b851..db84601 100644 --- a/test/expected/DR_Multichannel_5.1_single_source.aaf.expected +++ b/test/expected/DR_Multichannel_5.1_single_source.aaf.expected @@ -39,17 +39,38 @@ Media Essences : ================ - 0: Type: WAVE Length: 311952 06 Ch - 44100 Hz - 16 bits file: file://localhost/C:/Users/user/Desktop/res/5.1-SMPTE-channel-identif.wav file_name: 5 + Audio[1] :: Format: WAVE - 06 ch - 44100 Hz - 16 bits Length: 311952 Name: "5" UniqueName: "5_5" + └── File: "file://localhost/C:/Users/user/Desktop/res/5.1-SMPTE-channel-identif.wav" + + Audio[2] :: Format: WAVE - 06 ch - 44100 Hz - 16 bits Length: 311952 Name: "5" UniqueName: "5_4" + └── File: "file://localhost/C:/Users/user/Desktop/res/5.1-SMPTE-channel-identif.wav" + + Audio[3] :: Format: WAVE - 06 ch - 44100 Hz - 16 bits Length: 311952 Name: "5" UniqueName: "5_3" + └── File: "file://localhost/C:/Users/user/Desktop/res/5.1-SMPTE-channel-identif.wav" + + Audio[4] :: Format: WAVE - 06 ch - 44100 Hz - 16 bits Length: 311952 Name: "5" UniqueName: "5_2" + └── File: "file://localhost/C:/Users/user/Desktop/res/5.1-SMPTE-channel-identif.wav" + + Audio[5] :: Format: WAVE - 06 ch - 44100 Hz - 16 bits Length: 311952 Name: "5" UniqueName: "5_1" + └── File: "file://localhost/C:/Users/user/Desktop/res/5.1-SMPTE-channel-identif.wav" + + Audio[6] :: Format: WAVE - 06 ch - 44100 Hz - 16 bits Length: 311952 Name: "5" UniqueName: "5" + └── File: "file://localhost/C:/Users/user/Desktop/res/5.1-SMPTE-channel-identif.wav" Tracks & Clips : ================ -VideoTrack (1) - edit_rate 24/1 (24.00) - "" -Track (1) - 5.1 - Gain: none - Pan: none - edit_rate: 48000/1 (48000.00) - "Audio 1" - Clip:0 Channel: 6 Gain: none GainAuto: none Start: 13215779 Len: 306787 End: 13522566 SrcOffset: 1837 - SourceFile: [ch all] 5 (5) - + VideoTrack[1] :: EditRate: 24/1 (24.00) + AudioTrack[1] :: EditRate: 48000/1 (48000.00) Format: 5.1 Name: "Audio 1" + └── Clip (1): Start: 13215779 Len: 306787 End: 13522566 SourceOffset: 1837 Channels: 6 + ├── SourceFile [ch 1]: "5" + ├── SourceFile [ch 2]: "5_1" + ├── SourceFile [ch 3]: "5_2" + ├── SourceFile [ch 4]: "5_3" + ├── SourceFile [ch 5]: "5_4" + └── SourceFile [ch 6]: "5_5" + diff --git a/test/expected/DR_Multichannel_7.1_single_source.aaf.expected b/test/expected/DR_Multichannel_7.1_single_source.aaf.expected index 596bc93..2e664aa 100644 --- a/test/expected/DR_Multichannel_7.1_single_source.aaf.expected +++ b/test/expected/DR_Multichannel_7.1_single_source.aaf.expected @@ -39,17 +39,46 @@ Media Essences : ================ - 0: Type: WAVE Length: 481171 08 Ch - 44100 Hz - 16 bits file: file://localhost/C:/Users/user/Desktop/res/7.1-SMPTE-channel-identif.wav file_name: 7 + Audio[1] :: Format: WAVE - 08 ch - 44100 Hz - 16 bits Length: 481171 Name: "7" UniqueName: "7_7" + └── File: "file://localhost/C:/Users/user/Desktop/res/7.1-SMPTE-channel-identif.wav" + + Audio[2] :: Format: WAVE - 08 ch - 44100 Hz - 16 bits Length: 481171 Name: "7" UniqueName: "7_6" + └── File: "file://localhost/C:/Users/user/Desktop/res/7.1-SMPTE-channel-identif.wav" + + Audio[3] :: Format: WAVE - 08 ch - 44100 Hz - 16 bits Length: 481171 Name: "7" UniqueName: "7_5" + └── File: "file://localhost/C:/Users/user/Desktop/res/7.1-SMPTE-channel-identif.wav" + + Audio[4] :: Format: WAVE - 08 ch - 44100 Hz - 16 bits Length: 481171 Name: "7" UniqueName: "7_4" + └── File: "file://localhost/C:/Users/user/Desktop/res/7.1-SMPTE-channel-identif.wav" + + Audio[5] :: Format: WAVE - 08 ch - 44100 Hz - 16 bits Length: 481171 Name: "7" UniqueName: "7_3" + └── File: "file://localhost/C:/Users/user/Desktop/res/7.1-SMPTE-channel-identif.wav" + + Audio[6] :: Format: WAVE - 08 ch - 44100 Hz - 16 bits Length: 481171 Name: "7" UniqueName: "7_2" + └── File: "file://localhost/C:/Users/user/Desktop/res/7.1-SMPTE-channel-identif.wav" + + Audio[7] :: Format: WAVE - 08 ch - 44100 Hz - 16 bits Length: 481171 Name: "7" UniqueName: "7_1" + └── File: "file://localhost/C:/Users/user/Desktop/res/7.1-SMPTE-channel-identif.wav" + + Audio[8] :: Format: WAVE - 08 ch - 44100 Hz - 16 bits Length: 481171 Name: "7" UniqueName: "7" + └── File: "file://localhost/C:/Users/user/Desktop/res/7.1-SMPTE-channel-identif.wav" Tracks & Clips : ================ -VideoTrack (1) - edit_rate 24/1 (24.00) - "" -Track (1) - 7.1 - Gain: none - Pan: none - edit_rate: 48000/1 (48000.00) - "Audio 1" - Clip:0 Channel: 8 Gain: none GainAuto: none Start: 13215780 Len: 475183 End: 13690964 SrcOffset: 1837 - SourceFile: [ch all] 7 (7) - + VideoTrack[1] :: EditRate: 24/1 (24.00) + AudioTrack[1] :: EditRate: 48000/1 (48000.00) Format: 7.1 Name: "Audio 1" + └── Clip (1): Start: 13215780 Len: 475183 End: 13690964 SourceOffset: 1837 Channels: 8 + ├── SourceFile [ch 1]: "7" + ├── SourceFile [ch 2]: "7_1" + ├── SourceFile [ch 3]: "7_2" + ├── SourceFile [ch 4]: "7_3" + ├── SourceFile [ch 5]: "7_4" + ├── SourceFile [ch 6]: "7_5" + ├── SourceFile [ch 7]: "7_6" + └── SourceFile [ch 8]: "7_7" + diff --git a/test/expected/DR_Multichannel_stereo_single_source.aaf.expected b/test/expected/DR_Multichannel_stereo_single_source.aaf.expected index aea3731..3c94af4 100644 --- a/test/expected/DR_Multichannel_stereo_single_source.aaf.expected +++ b/test/expected/DR_Multichannel_stereo_single_source.aaf.expected @@ -39,17 +39,22 @@ Media Essences : ================ - 0: Type: WAVE Length: 43117 02 Ch - 22050 Hz - 16 bits file: file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav file_name: stereo-identif + Audio[1] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "stereo-identif" UniqueName: "stereo-identif_1" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + + Audio[2] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "stereo-identif" UniqueName: "stereo-identif" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" Tracks & Clips : ================ -VideoTrack (1) - edit_rate 24/1 (24.00) - "" -Track (1) - STEREO - Gain: none - Pan: none - edit_rate: 48000/1 (48000.00) - "Audio 1" - Clip:0 Channel: 2 Gain: none GainAuto: none Start: 13215779 Len: 80238 End: 13296017 SrcOffset: 1837 - SourceFile: [ch all] stereo-identif (stereo-identif) - + VideoTrack[1] :: EditRate: 24/1 (24.00) + AudioTrack[1] :: EditRate: 48000/1 (48000.00) Format: STEREO Name: "Audio 1" + └── Clip (1): Start: 13215779 Len: 80238 End: 13296017 SourceOffset: 1837 Channels: 2 + ├── SourceFile [ch 1]: "stereo-identif" + └── SourceFile [ch 2]: "stereo-identif_1" + diff --git a/test/expected/DR_Stereo_Clip_Positioning.aaf.expected b/test/expected/DR_Stereo_Clip_Positioning.aaf.expected index 6121a94..485daf3 100644 --- a/test/expected/DR_Stereo_Clip_Positioning.aaf.expected +++ b/test/expected/DR_Stereo_Clip_Positioning.aaf.expected @@ -39,26 +39,52 @@ Media Essences : ================ - 0: Type: WAVE Length: 43117 02 Ch - 22050 Hz - 16 bits file: file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav file_name: sample-accuracy-173459321 - 1: Type: WAVE Length: 43117 02 Ch - 22050 Hz - 16 bits file: file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav file_name: tc-accurate-01:00:09:00-173232000 - 2: Type: WAVE Length: 43117 02 Ch - 22050 Hz - 16 bits file: file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav file_name: sample-accurate-173000000 - 3: Type: WAVE Length: 43117 02 Ch - 22050 Hz - 16 bits file: file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav file_name: stereo-identif + Audio[1] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "sample-accuracy-173459321" UniqueName: "sample-accuracy-173459321_1" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + Audio[2] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "sample-accuracy-173459321" UniqueName: "sample-accuracy-173459321" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" -Tracks & Clips : -================ + Audio[3] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "tc-accurate-01:00:09:00-173232000" UniqueName: "tc-accurate-01:00:09:00-173232000_1" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + + Audio[4] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "tc-accurate-01:00:09:00-173232000" UniqueName: "tc-accurate-01:00:09:00-173232000" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + + Audio[5] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "sample-accurate-173000000" UniqueName: "sample-accurate-173000000_1" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" -VideoTrack (1) - edit_rate 24/1 (24.00) - "" -Track (1) - STEREO - Gain: none - Pan: none - edit_rate: 48000/1 (48000.00) - "Audio 1" - Clip:0 Channel: 2 Gain: none GainAuto: none Start: 172800000 Len: 93860 End: 172893860 SrcOffset: 0 - SourceFile: [ch all] stereo-identif (stereo-identif) - Clip:1 Channel: 2 Gain: none GainAuto: none Start: 173000000 Len: 93860 End: 173093860 SrcOffset: 0 - SourceFile: [ch all] sample-accurate-173000000 (sample-accurate-173000000) - Clip:2 Channel: 2 Gain: none GainAuto: none Start: 173232000 Len: 93860 End: 173325860 SrcOffset: 0 - SourceFile: [ch all] tc-accurate-01:00:09:00-173232000 (tc-accurate-01:00:09:00-173232000) - Clip:3 Channel: 2 Gain: none GainAuto: none Start: 173459321 Len: 93860 End: 173553181 SrcOffset: 0 - SourceFile: [ch all] sample-accuracy-173459321 (sample-accuracy-173459321) + Audio[6] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "sample-accurate-173000000" UniqueName: "sample-accurate-173000000" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + Audio[7] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "stereo-identif" UniqueName: "stereo-identif_1" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + Audio[8] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 43117 Name: "stereo-identif" UniqueName: "stereo-identif" + └── File: "file://localhost/C:/Users/user/Desktop/res/stereo-identif.wav" + + +Tracks & Clips : +================ + VideoTrack[1] :: EditRate: 24/1 (24.00) + + + AudioTrack[1] :: EditRate: 48000/1 (48000.00) Format: STEREO Name: "Audio 1" + ├── Clip (1): Start: 172800000 Len: 93860 End: 172893860 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "stereo-identif" + │ └── SourceFile [ch 2]: "stereo-identif_1" + │ + ├── Clip (2): Start: 173000000 Len: 93860 End: 173093860 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "sample-accurate-173000000" + │ └── SourceFile [ch 2]: "sample-accurate-173000000_1" + │ + ├── Clip (3): Start: 173232000 Len: 93860 End: 173325860 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "tc-accurate-01:00:09:00-173232000" + │ └── SourceFile [ch 2]: "tc-accurate-01:00:09:00-173232000_1" + │ + └── Clip (4): Start: 173459321 Len: 93860 End: 173553181 SourceOffset: 0 Channels: 2 + ├── SourceFile [ch 1]: "sample-accuracy-173459321" + └── SourceFile [ch 2]: "sample-accuracy-173459321_1" + diff --git a/test/expected/MC_Audio_Levels.aaf.expected b/test/expected/MC_Audio_Levels.aaf.expected new file mode 100644 index 0000000..f944a8d --- /dev/null +++ b/test/expected/MC_Audio_Levels.aaf.expected @@ -0,0 +1,98 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-27 17:46:27.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-27 17:46:27.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xbb3d8e34 0x8494 0x4a2d { 0x9a 0xfa 0x17 0xdd 0x02 0xa7 0x9b 0xe7 } } + + + + Composition Name : MC_Audio_Levels.Exporté.14 + + TC EditRrate : 30000/1001 + TC FPS : 30 NDF + + Composition Start (EU) : 108000 + Composition Start (samples) : 172972800 + Composition Start : 01:00:00:00 + + Composition End (EU) : 108090 (EditRate: 30000/1001) + Composition End (samples) : 173116944 + Composition End : 01:00:03:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 144144 Name: "A1000hz-18dbs16b44.1k.wav" UniqueName: "A1000hz-18dbs16b44.1k.wav" + └── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/A1000hz-18A01.65A40B55B067A.mxf" + + Audio[2] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 144144 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A40B01E984A.mxf" + └── Metadata: + - Name: "Comments" Text: "This is a Source Media Comment." + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 30000/1001 (29.97) + + + AudioTrack[1] :: EditRate: 30000/1001 (29.97) Format: MONO + ├── Clip (1): Start: 172972800 Len: 48048 End: 173020848 SourceOffset: 48048 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 0.433333 _value: 0.004842 (-46.3 dB) + │ _time: 0.966667 _value: 1.000000 (+00.0 dB) + │ + └── Clip (2): Start: 173020848 Len: 48048 End: 173068896 SourceOffset: 64064 Channels: 1 Gain: +03.0 dB VolumeAutomation: YES + ├── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + └── Clip Volume Automation ────────────────────── + _time: 0.000000 _value: 1.000000 (+00.0 dB) + _time: 0.366667 _value: 0.000030 (-90.4 dB) + _time: 0.666667 _value: 2.871290 (+09.2 dB) + _time: 0.966667 _value: 1.000000 (+00.0 dB) + + + AudioTrack[2] :: EditRate: 30000/1001 (29.97) Format: MONO + └── Clip (1): Start: 172972800 Len: 48048 End: 173020848 SourceOffset: 48048 Channels: 1 VolumeAutomation: YES + ├── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + └── Clip Volume Automation ────────────────────── + _time: 0.433333 _value: 2.511886 (+08.0 dB) + + + AudioTrack[3] :: EditRate: 30000/1001 (29.97) Format: MONO Solo: SOLO + └── Clip (1): Start: 172972800 Len: 48048 End: 173020848 SourceOffset: 0 Channels: 1 Gain: +02.0 dB ClipName: "1000hz-18dbs16b44.1k.wav.Sub.01" + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[4] :: EditRate: 30000/1001 (29.97) Format: MONO + └── Clip (1): Start: 172972800 Len: 144144 End: 173116944 SourceOffset: 0 Channels: 1 Gain: +01.5 dB + └── SourceFile [ch 1]: "A1000hz-18dbs16b44.1k.wav" + + + AudioTrack[5] :: EditRate: 30000/1001 (29.97) Format: MONO + └── Clip (1): Start: 172972800 Len: 144144 End: 173116944 SourceOffset: 0 Channels: 1 Gain: +06.0 dB + └── SourceFile [ch 1]: "A1000hz-18dbs16b44.1k.wav" + + diff --git a/test/expected/MC_Audio_Pan.aaf.expected b/test/expected/MC_Audio_Pan.aaf.expected new file mode 100644 index 0000000..2f9de8d --- /dev/null +++ b/test/expected/MC_Audio_Pan.aaf.expected @@ -0,0 +1,75 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 20:22:07.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 20:22:07.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x39f6cfeb 0xa9d9 0x42ef { 0xbf 0x82 0xa8 0x01 0xd3 0xc5 0xda 0x53 } } + + + + Composition Name : MC_Pan.Exporté.04 + + TC EditRrate : 30000/1001 + TC FPS : 30 NDF + + Composition Start (EU) : 108000 + Composition Start (samples) : 172972800 + Composition Start : 01:00:00:00 + + Composition End (EU) : 108060 (EditRate: 30000/1001) + Composition End (samples) : 173068896 + Composition End : 01:00:02:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 144144 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A40B01E984A.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 30000/1001 (29.97) + + + AudioTrack[1] :: EditRate: 30000/1001 (29.97) Format: MONO Pan: (A) + ├── Clip (1): Start: 172972800 Len: 48048 End: 173020848 SourceOffset: 48048 Channels: 1 + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + ├── Clip (2): Start: 173020848 Len: 48048 End: 173068896 SourceOffset: 48048 Channels: 1 + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + └── Track Pan Automation ───────────── + _time: 0.000000 _value: 0.000000 + _time: 0.483333 _value: 0.000000 + _time: 0.500000 _value: 0.500000 + _time: 0.633333 _value: 1.000000 + _time: 0.800000 _value: 0.000000 + _time: 0.983333 _value: 0.500000 + + AudioTrack[2] :: EditRate: 30000/1001 (29.97) Format: MONO Pan: 1.00 (R) + └── Clip (1): Start: 172972800 Len: 48048 End: 173020848 SourceOffset: 48048 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + diff --git a/test/expected/MC_Audio_Warp.aaf.expected b/test/expected/MC_Audio_Warp.aaf.expected new file mode 100644 index 0000000..cbcb568 --- /dev/null +++ b/test/expected/MC_Audio_Warp.aaf.expected @@ -0,0 +1,104 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-31 00:25:06.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-31 00:25:06.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xc29f777b 0x15c2 0x4650 { 0x9e 0xf1 0xec 0xf7 0xdb 0xc9 0xe9 0xec } } + + + + Composition Name : MC_Audio_Warp.Exporté.02 + + TC EditRrate : 25/1 + TC FPS : 25 NDF + + Composition Start (EU) : 90000 + Composition Start (samples) : 172800000 + Composition Start : 01:00:00:00 + + Composition End (EU) : 90121 (EditRate: 25/1) + Composition End (samples) : 173032320 + Composition End : 01:00:04:21 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Video[1] :: Length: 0 Name: "bbb_sunflower_1080p_30fps_normal" UniqueName: "bbb_sunflower_1080p_30fps_normal" + └── File: "file:///C%3A/Users/user/Downloads/bbb_sunflower_1080p_30fps_normal.mp4" + + + Audio[1] :: Format: PCM - 06 ch - 48000 Hz - 16 bits Length: 30457600 Name: "bbb_sunflower_1080p_30fps_normal" UniqueName: "bbb_sunflower_1080p_30fps_normal_1" + ├── File: "file:///C%3A/Users/user/Downloads/bbb_sunflower_1080p_30fps_normal.mp4" + └── Metadata: + - Name: "Video" Text: "QTFF" + + Audio[2] :: Format: - 00 ch - 0 Hz - 0 bits Length: 0 Name: "bbb_sunflower_1080p_30fps_normal" UniqueName: "bbb_sunflower_1080p_30fps_normal" + ├── File: "file:///C%3A/Users/user/Downloads/bbb_sunflower_1080p_30fps_normal.mp4" + └── Metadata: + - Name: "Video" Text: "QTFF" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 25/1 (25.00) + └── Clip (1): Start: 172800000 Len: 232320 End: 173032320 SourceOffset: 12506880 + + + + AudioTrack[1] :: EditRate: 25/1 (25.00) Format: MONO + └── Clip (1): Start: 172800000 Len: 192000 End: 172992000 SourceOffset: 10421760 Channels: 1 + └── SourceFile [ch 1]: "bbb_sunflower_1080p_30fps_normal" + + + AudioTrack[2] :: EditRate: 25/1 (25.00) Format: MONO + └── Clip (1): Start: 172800000 Len: 192000 End: 172992000 SourceOffset: 10421760 Channels: 1 + └── SourceFile [ch 2]: "bbb_sunflower_1080p_30fps_normal" + + + AudioTrack[3] :: EditRate: 25/1 (25.00) Format: MONO + └── Clip (1): Start: 172800000 Len: 192000 End: 172992000 SourceOffset: 10421760 Channels: 1 + └── SourceFile [ch 3]: "bbb_sunflower_1080p_30fps_normal_1" + + + AudioTrack[4] :: EditRate: 25/1 (25.00) Format: MONO + └── Clip (1): Start: 172800000 Len: 192000 End: 172992000 SourceOffset: 10421760 Channels: 1 + └── SourceFile [ch 4]: "bbb_sunflower_1080p_30fps_normal_1" + + + AudioTrack[5] :: EditRate: 25/1 (25.00) Format: MONO + └── Clip (1): Start: 172800000 Len: 192000 End: 172992000 SourceOffset: 10421760 Channels: 1 + └── SourceFile [ch 5]: "bbb_sunflower_1080p_30fps_normal_1" + + + AudioTrack[6] :: EditRate: 25/1 (25.00) Format: MONO + └── Clip (1): Start: 172800000 Len: 192000 End: 172992000 SourceOffset: 10421760 Channels: 1 + └── SourceFile [ch 6]: "bbb_sunflower_1080p_30fps_normal_1" + + + AudioTrack[7] :: EditRate: 25/1 (25.00) Format: MONO + └── Clip (1): Start: 172800000 Len: 192000 End: 172992000 SourceOffset: 10421760 Channels: 1 + └── SourceFile [ch 7]: "bbb_sunflower_1080p_30fps_normal_1" + + + AudioTrack[8] :: EditRate: 25/1 (25.00) Format: MONO + └── Clip (1): Start: 172800000 Len: 192000 End: 172992000 SourceOffset: 10421760 Channels: 1 + └── SourceFile [ch 8]: "bbb_sunflower_1080p_30fps_normal_1" + + diff --git a/test/expected/MC_Clip_Mute.aaf.expected b/test/expected/MC_Clip_Mute.aaf.expected new file mode 100644 index 0000000..efd7d77 --- /dev/null +++ b/test/expected/MC_Clip_Mute.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-15 01:14:43.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-15 01:14:43.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xaf8aee3d 0xb2aa 0x460c { 0xaa 0x9e 0x9f 0x6e 0xbc 0xc7 0x59 0xe1 } } + + + + Composition Name : MC_Mute.Exporté.01 + + TC EditRrate : 30000/1001 + TC FPS : 30 NDF + + Composition Start (EU) : 108000 + Composition Start (samples) : 172972800 + Composition Start : 01:00:00:00 + + Composition End (EU) : 108030 (EditRate: 30000/1001) + Composition End (samples) : 173020848 + Composition End : 01:00:01:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 144144 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A40B01E984A.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 30000/1001 (29.97) + + + AudioTrack[1] :: EditRate: 30000/1001 (29.97) Format: MONO + └── Clip (1): Start: 172972800 Len: 48048 End: 173020848 SourceOffset: 48048 Channels: 1 Mute: MUTE + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 30000/1001 (29.97) Format: Unknwn + diff --git a/test/expected/MC_Empty.aaf.expected b/test/expected/MC_Empty.aaf.expected new file mode 100644 index 0000000..f5319d5 --- /dev/null +++ b/test/expected/MC_Empty.aaf.expected @@ -0,0 +1,46 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 20:56:25.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 20:56:25.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xc38cdb19 0xa46d 0x4bdc { 0xbc 0xec 0xb7 0xc3 0xd3 0xeb 0xf4 0x69 } } + + + + Composition Name : MC_Empty.Exporté.02 + + TC EditRrate : 30000/1001 + TC FPS : 30 NDF + + Composition Start (EU) : 108000 + Composition Start (samples) : 0 + Composition Start : 01:00:00:00 + + Composition End (EU) : 108000 (EditRate: 0/0) + Composition End (samples) : 108000 + Composition End : 01:00:00:00 + + Dominant Sample Rate : 0 + Dominant Sample Size : 0 bits + + +Media Essences : +================ + + +Tracks & Clips : +================ + + diff --git a/test/expected/MC_Fades.aaf.expected b/test/expected/MC_Fades.aaf.expected new file mode 100644 index 0000000..35de531 --- /dev/null +++ b/test/expected/MC_Fades.aaf.expected @@ -0,0 +1,115 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-27 14:15:59.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-27 14:15:59.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x84487039 0x1959 0x41f6 { 0x99 0x0d 0xe7 0xf5 0x16 0xae 0x62 0xb9 } } + + + + Composition Name : MC_Fades.Exporté.05 + + TC EditRrate : 30000/1001 + TC FPS : 30 NDF + + Composition Start (EU) : 108000 + Composition Start (samples) : 172972800 + Composition Start : 01:00:00:00 + + Composition End (EU) : 108256 (EditRate: 30000/1001) + Composition End (samples) : 173382810 + Composition End : 01:00:08:16 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 94496 Name: "stereo-identif.wav" UniqueName: "stereo-identif.wav_1" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/stereo-ideA02.65B526B69235A.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\res\stereo-identif.wav" + + Audio[2] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 94496 Name: "stereo-identif.wav" UniqueName: "stereo-identif.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/stereo-ideA01.65B526B69015A.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\res\stereo-identif.wav" + + Audio[3] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 144144 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A40B01E984A.mxf" + └── Metadata: + - Name: "Comments" Text: "This is a Source Media Comment." + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 30000/1001 (29.97) + + + AudioTrack[1] :: EditRate: 30000/1001 (29.97) Format: MONO + ├── Clip (1): Start: 172972800 Len: 48048 End: 173020848 SourceOffset: 48048 Channels: 1 FadeIn: CURV_LIN (8008) FadeOut: CURV_LIN (8008) + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + ├── Clip (2): Start: 173036864 Len: 32032 End: 173068896 SourceOffset: 48048 Channels: 1 + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + ├── X-FADE: CURV_LIN Length: 8008 CutPoint: 3203 + │ + ├── Clip (3): Start: 173060888 Len: 40040 End: 173100928 SourceOffset: 52852 Channels: 1 + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + ├── X-FADE: CURV_PWR Length: 8008 CutPoint: 3203 + │ + └── Clip (4): Start: 173092920 Len: 24024 End: 173116944 SourceOffset: 51251 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 30000/1001 (29.97) Format: MONO + └── Clip (1): Start: 172972800 Len: 48048 End: 173020848 SourceOffset: 48048 Channels: 1 FadeIn: CURV_PWR (8008) FadeOut: CURV_PWR (8008) + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[3] :: EditRate: 30000/1001 (29.97) Format: STEREO + ├── Clip (1): Start: 172972800 Len: 94494 End: 173067295 SourceOffset: 0 Channels: 2 FadeIn: CURV_LIN (8008) FadeOut: CURV_LIN (8008) + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + ├── Clip (2): Start: 173068896 Len: 94494 End: 173163391 SourceOffset: 0 Channels: 2 FadeIn: CURV_PWR (8008) FadeOut: CURV_PWR (8008) + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + ├── Clip (3): Start: 173166594 Len: 83283 End: 173249877 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + ├── X-FADE: CURV_LIN Length: 16016 CutPoint: 8008 + │ + ├── Clip (4): Start: 173233861 Len: 80080 End: 173313941 SourceOffset: 3203 Channels: 2 + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + ├── X-FADE: CURV_PWR Length: 16016 CutPoint: 8008 + │ + └── Clip (5): Start: 173297925 Len: 84884 End: 173382810 SourceOffset: 9609 Channels: 2 + ├── SourceFile [ch 1]: "stereo-identif.wav" + └── SourceFile [ch 2]: "stereo-identif.wav_1" + + diff --git a/test/expected/MC_Markers.aaf.expected b/test/expected/MC_Markers.aaf.expected new file mode 100644 index 0000000..b08254e --- /dev/null +++ b/test/expected/MC_Markers.aaf.expected @@ -0,0 +1,72 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 21:07:09.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 21:07:09.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xeb663fe0 0x8cc1 0x4622 { 0xad 0xd9 0xf5 0x3a 0xb3 0x87 0x33 0xc9 } } + + + + Composition Name : MC_Markers.Exporté.03 + + TC EditRrate : 30000/1001 + TC FPS : 30 NDF + + Composition Start (EU) : 108000 + Composition Start (samples) : 172972800 + Composition Start : 01:00:00:00 + + Composition End (EU) : 108030 (EditRate: 30000/1001) + Composition End (samples) : 173020848 + Composition End : 01:00:01:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 144144 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A40B01E984A.mxf" + └── Metadata: + - Name: "Comments" Text: "This is a Source Media Comment." + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 30000/1001 (29.97) + + + AudioTrack[1] :: EditRate: 30000/1001 (29.97) Format: MONO + └── Clip (1): Start: 172972800 Len: 48048 End: 173020848 SourceOffset: 48048 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 30000/1001 (29.97) Format: MONO + └── Clip (1): Start: 172972800 Len: 6406 End: 172979207 SourceOffset: 48048 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + +Markers : +========= + + Marker[0]: EditRate: 30000/1001 (29.97) Start: 172988816 Length: 0 Color: #ffa1662fa419 Label: "ABC" Comment: "I'm a Marker on track A1, at pos 01:00:00:10, I last 1 frame, my color is red, my name is ABC" + Marker[1]: EditRate: 30000/1001 (29.97) Start: 173019247 Length: 0 Color: #3333cccccccc Label: "DEF" Comment: "I'm a Marker on track A2, at pos 01:00:00:29, I last 1 frame, my color is cyan, my name is DEF" + Marker[2]: EditRate: 30000/1001 (29.97) Start: 172972800 Length: 6406 Color: #65e665e69919 Label: "XYZ" Comment: "I'm a Marker on track TC1, at pos 01:00:00:00, I last 4 frames, my color is yellow, my name is XYZ" diff --git a/test/expected/MC_Metadata.aaf.expected b/test/expected/MC_Metadata.aaf.expected new file mode 100644 index 0000000..64e4842 --- /dev/null +++ b/test/expected/MC_Metadata.aaf.expected @@ -0,0 +1,84 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-27 13:54:16.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-27 13:54:16.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x8638c4e7 0x1d69 0x4ed4 { 0xb3 0x70 0xb5 0xa8 0xf4 0xe6 0xd6 0x6d } } + + + + Composition Name : MC_Metadata.Exporté.02 + + TC EditRrate : 30000/1001 + TC FPS : 30 NDF + + Composition Start (EU) : 108000 + Composition Start (samples) : 172972800 + Composition Start : 01:00:00:00 + + Composition End (EU) : 108090 (EditRate: 30000/1001) + Composition End (samples) : 173116944 + Composition End : 01:00:03:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comments" Text: "This is a composition comment" + - Name: "TapeID" Text: "compo. tapeid" + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 144144 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65B20470E378A.mxf" + └── Metadata: + - Name: "Comments" Text: "This is a source file comment" + - Name: "Journalist" Text: "M. Bakounine" + - Name: "Scene" Text: "P21" + - Name: "Take" Text: "3" + - Name: "Production" Text: "horlaprod" + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 30000/1001 (29.97) + + + AudioTrack[1] :: EditRate: 30000/1001 (29.97) Format: MONO + └── Clip (1): Start: 172972800 Len: 144144 End: 173116944 SourceOffset: 0 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 30000/1001 (29.97) Format: MONO + └── Clip (1): Start: 173020848 Len: 48048 End: 173068896 SourceOffset: 48048 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[3] :: EditRate: 30000/1001 (29.97) Format: MONO + └── Clip (1): Start: 173020848 Len: 48048 End: 173068896 SourceOffset: 0 Channels: 1 ClipName: "1000hz-18dbs16b44.1k.wav.Sub.01" + ├── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + └── Metadata ──────────────────────────────────── + - Name: "Comments" Text: "sub. This is a sub clip comment" + - Name: "Production" Text: "sub. horlaprod" + - Name: "Journalist" Text: "sub. M. Bakounine" + - Name: "_COMMENT" Text: "This is a timeline clip note" + + diff --git a/test/expected/MC_TC_100.aaf.expected b/test/expected/MC_TC_100.aaf.expected new file mode 100644 index 0000000..aa453c4 --- /dev/null +++ b/test/expected/MC_TC_100.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 22:27:10.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 22:27:10.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x7191554d 0x35e0 0x407f { 0xb0 0xe1 0xbb 0x44 0xb2 0xbc 0x10 0xca } } + + + + Composition Name : MC_TC_100.Exporté.01 + + TC EditRrate : 100/1 + TC FPS : 100 NDF + + Composition Start (EU) : 360000 + Composition Start (samples) : 172800000 + Composition Start : 01:00:00:00 + + Composition End (EU) : 361300 (EditRate: 100/1) + Composition End (samples) : 173424000 + Composition End : 01:00:13:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03:00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A92634D1AAA.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 100/1 (100.00) + + + AudioTrack[1] :: EditRate: 100/1 (100.00) Format: MONO + └── Clip (1): Start: 01:00:10:00 Len: 00:00:03:00 End: 01:00:13:00 SourceOffset: 00:00:00:00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 100/1 (100.00) Format: Unknwn + diff --git a/test/expected/MC_TC_119.88_DF.aaf.expected b/test/expected/MC_TC_119.88_DF.aaf.expected new file mode 100644 index 0000000..6eae11b --- /dev/null +++ b/test/expected/MC_TC_119.88_DF.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 22:29:34.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 22:29:34.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x205472dc 0x1a77 0x434d { 0x84 0xd7 0xfe 0x72 0x93 0xbc 0x4e 0x1a } } + + + + Composition Name : MC_TC_119.88_DF.Exporté.01 + + TC EditRrate : 11988/100 + TC FPS : 120 DF + + Composition Start (EU) : 431568 + Composition Start (samples) : 172800003 + Composition Start : 01:00:00;00 + + Composition End (EU) : 433128 (EditRate: 11988/100) + Composition End (samples) : 173424628 + Composition End : 01:00:13;00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:02;119 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A9268189BAA.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 11988/100 (119.88) + + + AudioTrack[1] :: EditRate: 11988/100 (119.88) Format: MONO + └── Clip (1): Start: 01:00:10;00 Len: 00:00:03;00 End: 01:00:13;00 SourceOffset: 00:00:00;00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 11988/100 (119.88) Format: Unknwn + diff --git a/test/expected/MC_TC_119.88_NDF.aaf.expected b/test/expected/MC_TC_119.88_NDF.aaf.expected new file mode 100644 index 0000000..17b4e67 --- /dev/null +++ b/test/expected/MC_TC_119.88_NDF.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 22:29:07.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 22:29:07.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xdc608d09 0x6793 0x4f38 { 0x93 0x78 0x40 0x34 0x49 0x61 0x67 0x52 } } + + + + Composition Name : MC_TC_119.88_NDF.Exporté.01 + + TC EditRrate : 11988/100 + TC FPS : 120 NDF + + Composition Start (EU) : 432000 + Composition Start (samples) : 172972976 + Composition Start : 01:00:00:00 + + Composition End (EU) : 433560 (EditRate: 11988/100) + Composition End (samples) : 173597601 + Composition End : 01:00:13:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:02:119 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A9268189BAA.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 11988/100 (119.88) + + + AudioTrack[1] :: EditRate: 11988/100 (119.88) Format: MONO + └── Clip (1): Start: 01:00:10:00 Len: 00:00:03:00 End: 01:00:13:00 SourceOffset: 00:00:00:00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 11988/100 (119.88) Format: Unknwn + diff --git a/test/expected/MC_TC_120_DF.aaf.expected b/test/expected/MC_TC_120_DF.aaf.expected new file mode 100644 index 0000000..97047f2 --- /dev/null +++ b/test/expected/MC_TC_120_DF.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 22:31:32.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 22:31:32.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x73aed159 0xcf91 0x4e7b { 0x87 0xe8 0x93 0xa3 0x25 0x88 0xc3 0xc4 } } + + + + Composition Name : MC_TC_120_DF.Exporté.01 + + TC EditRrate : 120/1 + TC FPS : 120 DF + + Composition Start (EU) : 431568 + Composition Start (samples) : 172627200 + Composition Start : 01:00:00;00 + + Composition End (EU) : 433128 (EditRate: 120/1) + Composition End (samples) : 173251200 + Composition End : 01:00:13;00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03;00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A926D3E07FA.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 120/1 (120.00) + + + AudioTrack[1] :: EditRate: 120/1 (120.00) Format: MONO + └── Clip (1): Start: 01:00:10;00 Len: 00:00:03;00 End: 01:00:13;00 SourceOffset: 00:00:00;00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 120/1 (120.00) Format: Unknwn + diff --git a/test/expected/MC_TC_120_NDF.aaf.expected b/test/expected/MC_TC_120_NDF.aaf.expected new file mode 100644 index 0000000..a07ce29 --- /dev/null +++ b/test/expected/MC_TC_120_NDF.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 22:31:07.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 22:31:07.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xd152b3f5 0x2266 0x4ccc { 0x96 0xc7 0x9f 0x75 0x72 0x6a 0xb2 0x2c } } + + + + Composition Name : MC_TC_120_NDF.Exporté.01 + + TC EditRrate : 120/1 + TC FPS : 120 NDF + + Composition Start (EU) : 432000 + Composition Start (samples) : 172800000 + Composition Start : 01:00:00:00 + + Composition End (EU) : 433560 (EditRate: 120/1) + Composition End (samples) : 173424000 + Composition End : 01:00:13:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03:00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A926D3E07FA.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 120/1 (120.00) + + + AudioTrack[1] :: EditRate: 120/1 (120.00) Format: MONO + └── Clip (1): Start: 01:00:10:00 Len: 00:00:03:00 End: 01:00:13:00 SourceOffset: 00:00:00:00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 120/1 (120.00) Format: Unknwn + diff --git a/test/expected/MC_TC_23.976.aaf.expected b/test/expected/MC_TC_23.976.aaf.expected new file mode 100644 index 0000000..59fe748 --- /dev/null +++ b/test/expected/MC_TC_23.976.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 21:48:32.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 21:48:32.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x128eead1 0x3f28 0x4440 { 0x97 0xdb 0x3b 0xc8 0x93 0xb4 0x1b 0x8e } } + + + + Composition Name : MC_TC_23.976.Exporté.01 + + TC EditRrate : 24000/1001 + TC FPS : 24 NDF + + Composition Start (EU) : 86400 + Composition Start (samples) : 172972795 + Composition Start : 01:00:00:00 + + Composition End (EU) : 86712 (EditRate: 24000/1001) + Composition End (samples) : 173597419 + Composition End : 01:00:13:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03:00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A91EF8D674A.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 24000/1001 (23.98) + + + AudioTrack[1] :: EditRate: 24000/1001 (23.98) Format: MONO + └── Clip (1): Start: 01:00:10:00 Len: 00:00:03:00 End: 01:00:13:00 SourceOffset: 00:00:00:00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 24000/1001 (23.98) Format: Unknwn + diff --git a/test/expected/MC_TC_24.aaf.expected b/test/expected/MC_TC_24.aaf.expected new file mode 100644 index 0000000..714590b --- /dev/null +++ b/test/expected/MC_TC_24.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 21:50:11.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 21:50:11.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x4b3f8fd7 0x0c56 0x499b { 0xaf 0xe0 0xe3 0x33 0xbd 0xe4 0x10 0x36 } } + + + + Composition Name : MC_TC_24.Exporté.01 + + TC EditRrate : 24/1 + TC FPS : 24 NDF + + Composition Start (EU) : 86400 + Composition Start (samples) : 172800000 + Composition Start : 01:00:00:00 + + Composition End (EU) : 86712 (EditRate: 24/1) + Composition End (samples) : 173424000 + Composition End : 01:00:13:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03:00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A91FA88295A.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 24/1 (24.00) + + + AudioTrack[1] :: EditRate: 24/1 (24.00) Format: MONO + └── Clip (1): Start: 01:00:10:00 Len: 00:00:03:00 End: 01:00:13:00 SourceOffset: 00:00:00:00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 24/1 (24.00) Format: Unknwn + diff --git a/test/expected/MC_TC_25.aaf.expected b/test/expected/MC_TC_25.aaf.expected new file mode 100644 index 0000000..15e1363 --- /dev/null +++ b/test/expected/MC_TC_25.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 21:51:01.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 21:51:01.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x2a3f8287 0x540b 0x4845 { 0xb3 0x40 0xe5 0x37 0x80 0xd3 0x82 0xf7 } } + + + + Composition Name : MC_TC_25.Exporté.01 + + TC EditRrate : 25/1 + TC FPS : 25 NDF + + Composition Start (EU) : 90000 + Composition Start (samples) : 172800000 + Composition Start : 01:00:00:00 + + Composition End (EU) : 90325 (EditRate: 25/1) + Composition End (samples) : 173424000 + Composition End : 01:00:13:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03:00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A91FCEF2B6A.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 25/1 (25.00) + + + AudioTrack[1] :: EditRate: 25/1 (25.00) Format: MONO + └── Clip (1): Start: 01:00:10:00 Len: 00:00:03:00 End: 01:00:13:00 SourceOffset: 00:00:00:00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 25/1 (25.00) Format: Unknwn + diff --git a/test/expected/MC_TC_29.97_DF.aaf.expected b/test/expected/MC_TC_29.97_DF.aaf.expected new file mode 100644 index 0000000..ff80c8e --- /dev/null +++ b/test/expected/MC_TC_29.97_DF.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 21:54:27.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 21:54:27.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xfec8e739 0xb000 0x468f { 0xb6 0x77 0xda 0xdc 0xae 0x06 0x08 0xd1 } } + + + + Composition Name : MC_TC_29.97_DF.Exporté.01 + + TC EditRrate : 30000/1001 + TC FPS : 30 DF + + Composition Start (EU) : 107892 + Composition Start (samples) : 172799828 + Composition Start : 01:00:00;00 + + Composition End (EU) : 108282 (EditRate: 30000/1001) + Composition End (samples) : 173424452 + Composition End : 01:00:13;00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03;00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A92001C747A.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 30000/1001 (29.97) + + + AudioTrack[1] :: EditRate: 30000/1001 (29.97) Format: MONO + └── Clip (1): Start: 01:00:10;00 Len: 00:00:03;00 End: 01:00:13;00 SourceOffset: 00:00:00;00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 30000/1001 (29.97) Format: Unknwn + diff --git a/test/expected/MC_TC_29.97_NDF.aaf.expected b/test/expected/MC_TC_29.97_NDF.aaf.expected new file mode 100644 index 0000000..1d2d465 --- /dev/null +++ b/test/expected/MC_TC_29.97_NDF.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 21:53:10.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 21:53:10.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xda71781f 0x8f9d 0x40b6 { 0xa3 0x75 0x81 0xd5 0xab 0x32 0x00 0x3e } } + + + + Composition Name : MC_TC_29.97_NDF.Exporté.01 + + TC EditRrate : 30000/1001 + TC FPS : 30 NDF + + Composition Start (EU) : 108000 + Composition Start (samples) : 172972800 + Composition Start : 01:00:00:00 + + Composition End (EU) : 108390 (EditRate: 30000/1001) + Composition End (samples) : 173597424 + Composition End : 01:00:13:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03:00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A92001C747A.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 30000/1001 (29.97) + + + AudioTrack[1] :: EditRate: 30000/1001 (29.97) Format: MONO + └── Clip (1): Start: 01:00:10:00 Len: 00:00:03:00 End: 01:00:13:00 SourceOffset: 00:00:00:00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 30000/1001 (29.97) Format: Unknwn + diff --git a/test/expected/MC_TC_30_DF.aaf.expected b/test/expected/MC_TC_30_DF.aaf.expected new file mode 100644 index 0000000..650c044 --- /dev/null +++ b/test/expected/MC_TC_30_DF.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 22:21:51.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 22:21:51.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xb16d1dc7 0xa63e 0x46fd { 0x9c 0xdf 0x68 0x3f 0x54 0x72 0xd5 0x48 } } + + + + Composition Name : MC_TC_30_DF.Exporté.02 + + TC EditRrate : 30/1 + TC FPS : 30 DF + + Composition Start (EU) : 107892 + Composition Start (samples) : 172627200 + Composition Start : 01:00:00;00 + + Composition End (EU) : 108282 (EditRate: 30/1) + Composition End (samples) : 173251200 + Composition End : 01:00:13;00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03;00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A924A2102EA.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 30/1 (30.00) + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO + └── Clip (1): Start: 01:00:10;00 Len: 00:00:03;00 End: 01:00:13;00 SourceOffset: 00:00:00;00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 30/1 (30.00) Format: Unknwn + diff --git a/test/expected/MC_TC_30_NDF.aaf.expected b/test/expected/MC_TC_30_NDF.aaf.expected new file mode 100644 index 0000000..9efabd2 --- /dev/null +++ b/test/expected/MC_TC_30_NDF.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 22:18:32.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 22:18:32.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x002f9135 0x8f0f 0x41d3 { 0xa3 0x9c 0xf9 0x2a 0xa4 0x79 0x32 0xf3 } } + + + + Composition Name : MC_TC_30_NDF.Exporté.01 + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 108000 + Composition Start (samples) : 172800000 + Composition Start : 01:00:00:00 + + Composition End (EU) : 108390 (EditRate: 30/1) + Composition End (samples) : 173424000 + Composition End : 01:00:13:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03:00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A924A2102EA.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 30/1 (30.00) + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO + └── Clip (1): Start: 01:00:10:00 Len: 00:00:03:00 End: 01:00:13:00 SourceOffset: 00:00:00:00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 30/1 (30.00) Format: Unknwn + diff --git a/test/expected/MC_TC_50.aaf.expected b/test/expected/MC_TC_50.aaf.expected new file mode 100644 index 0000000..00ef969 --- /dev/null +++ b/test/expected/MC_TC_50.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 22:20:35.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 22:20:35.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xd26ba408 0x1e17 0x4b70 { 0x98 0x7c 0xb9 0x32 0x0d 0x13 0x1e 0xf7 } } + + + + Composition Name : MC_TC_50.Exporté.01 + + TC EditRrate : 50/1 + TC FPS : 50 NDF + + Composition Start (EU) : 180000 + Composition Start (samples) : 172800000 + Composition Start : 01:00:00:00 + + Composition End (EU) : 180650 (EditRate: 50/1) + Composition End (samples) : 173424000 + Composition End : 01:00:13:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03:00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A924FF1087A.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 50/1 (50.00) + + + AudioTrack[1] :: EditRate: 50/1 (50.00) Format: MONO + └── Clip (1): Start: 01:00:10:00 Len: 00:00:03:00 End: 01:00:13:00 SourceOffset: 00:00:00:00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 50/1 (50.00) Format: Unknwn + diff --git a/test/expected/MC_TC_59.94_DF.aaf.expected b/test/expected/MC_TC_59.94_DF.aaf.expected new file mode 100644 index 0000000..db52d1f --- /dev/null +++ b/test/expected/MC_TC_59.94_DF.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 22:24:07.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 22:24:07.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xa90bec17 0x70d8 0x4a1f { 0x9e 0xa3 0xa2 0x10 0xfd 0x5d 0x24 0x08 } } + + + + Composition Name : MC_TC_59.94_DF.Exporté.01 + + TC EditRrate : 60000/1001 + TC FPS : 60 DF + + Composition Start (EU) : 215784 + Composition Start (samples) : 172799828 + Composition Start : 01:00:00;00 + + Composition End (EU) : 216564 (EditRate: 60000/1001) + Composition End (samples) : 173424452 + Composition End : 01:00:13;00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03;00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A92589ED78A.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 60000/1001 (59.94) + + + AudioTrack[1] :: EditRate: 60000/1001 (59.94) Format: MONO + └── Clip (1): Start: 01:00:10;00 Len: 00:00:03;00 End: 01:00:13;00 SourceOffset: 00:00:00;00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 60000/1001 (59.94) Format: Unknwn + diff --git a/test/expected/MC_TC_59.94_NDF.aaf.expected b/test/expected/MC_TC_59.94_NDF.aaf.expected new file mode 100644 index 0000000..9e76e35 --- /dev/null +++ b/test/expected/MC_TC_59.94_NDF.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 22:23:40.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 22:23:40.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x34db2e64 0x9598 0x4425 { 0xb3 0xe6 0xb7 0xf6 0x81 0xc3 0xd3 0x02 } } + + + + Composition Name : MC_TC_59.94_NDF.Exporté.01 + + TC EditRrate : 60000/1001 + TC FPS : 60 NDF + + Composition Start (EU) : 216000 + Composition Start (samples) : 172972800 + Composition Start : 01:00:00:00 + + Composition End (EU) : 216780 (EditRate: 60000/1001) + Composition End (samples) : 173597424 + Composition End : 01:00:13:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03:00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A92589ED78A.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 60000/1001 (59.94) + + + AudioTrack[1] :: EditRate: 60000/1001 (59.94) Format: MONO + └── Clip (1): Start: 01:00:10:00 Len: 00:00:03:00 End: 01:00:13:00 SourceOffset: 00:00:00:00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 60000/1001 (59.94) Format: Unknwn + diff --git a/test/expected/MC_TC_60_DF.aaf.expected b/test/expected/MC_TC_60_DF.aaf.expected new file mode 100644 index 0000000..6f6b779 --- /dev/null +++ b/test/expected/MC_TC_60_DF.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 22:26:01.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 22:26:01.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x4af2b472 0xd879 0x40f0 { 0x93 0x9e 0x7b 0x63 0x63 0xd2 0x21 0x24 } } + + + + Composition Name : MC_TC_60_DF.Exporté.01 + + TC EditRrate : 60/1 + TC FPS : 60 DF + + Composition Start (EU) : 215784 + Composition Start (samples) : 172627200 + Composition Start : 01:00:00;00 + + Composition End (EU) : 216564 (EditRate: 60/1) + Composition End (samples) : 173251200 + Composition End : 01:00:13;00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03;00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A925E142ACA.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 60/1 (60.00) + + + AudioTrack[1] :: EditRate: 60/1 (60.00) Format: MONO + └── Clip (1): Start: 01:00:10;00 Len: 00:00:03;00 End: 01:00:13;00 SourceOffset: 00:00:00;00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 60/1 (60.00) Format: Unknwn + diff --git a/test/expected/MC_TC_60_NDF.aaf.expected b/test/expected/MC_TC_60_NDF.aaf.expected new file mode 100644 index 0000000..3de4bea --- /dev/null +++ b/test/expected/MC_TC_60_NDF.aaf.expected @@ -0,0 +1,62 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-18 22:25:35.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-18 22:25:35.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xecd9458d 0x4110 0x473c { 0xbc 0xe9 0x64 0xd0 0x65 0xd3 0xf1 0xf8 } } + + + + Composition Name : MC_TC_60_NDF.Exporté.01 + + TC EditRrate : 60/1 + TC FPS : 60 NDF + + Composition Start (EU) : 216000 + Composition Start (samples) : 172800000 + Composition Start : 01:00:00:00 + + Composition End (EU) : 216780 (EditRate: 60/1) + Composition End (samples) : 173424000 + Composition End : 01:00:13:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 00:00:03:00 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A925E142ACA.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 60/1 (60.00) + + + AudioTrack[1] :: EditRate: 60/1 (60.00) Format: MONO + └── Clip (1): Start: 01:00:10:00 Len: 00:00:03:00 End: 01:00:13:00 SourceOffset: 00:00:00:00 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 60/1 (60.00) Format: Unknwn + diff --git a/test/expected/MC_Track_Solo_Mute.aaf.expected b/test/expected/MC_Track_Solo_Mute.aaf.expected new file mode 100644 index 0000000..1157fda --- /dev/null +++ b/test/expected/MC_Track_Solo_Mute.aaf.expected @@ -0,0 +1,65 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-15 13:22:14.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Avid Technology, Inc. + ProductName : Avid Media Composer 23.12 + ProductVersion : 23.12.0.0 AAFVersionReleased (1) + ProductVersionString : Unknown version + ProductID : { 0xd0b7c06e 0xcd3d 0x4ad7 { 0xac 0xfb 0xf0 0x3a 0x4f 0x42 0xa2 0x31 } } + Date : 2024-01-15 13:22:14.00 + ToolkitVersion : 2.0.9.124 AAFVersionReleased (1) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x354f366d 0x0a56 0x4836 { 0x8d 0x6d 0xfa 0xd3 0xb9 0xa5 0xb3 0x49 } } + + + + Composition Name : MC_Track_Solo_Mute.Exporté.01 + + TC EditRrate : 30000/1001 + TC FPS : 30 NDF + + Composition Start (EU) : 108000 + Composition Start (samples) : 172972800 + Composition Start : 01:00:00:00 + + Composition End (EU) : 108030 (EditRate: 30000/1001) + Composition End (samples) : 173020848 + Composition End : 01:00:01:00 + + Dominant Sample Rate : 48000 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: PCM - 01 ch - 48000 Hz - 16 bits Length: 144144 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file:///D%3A/Avid%20MediaFiles/MXF/1/1000hz-18dA01.65A40B01E984A.mxf" + └── Metadata: + - Name: "UNC Path" Text: "C:\Users\user\Desktop\LibAAFTestFiles\res\1000hz-18dbs16b44.1k.wav" + - Name: "Shoot Date" Text: "2024-01-03" + - Name: "TapeID" Text: "1000hz-18dbs16b44.1k.wav" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 30000/1001 (29.97) + + + AudioTrack[1] :: EditRate: 30000/1001 (29.97) Format: MONO Solo: SOLO + └── Clip (1): Start: 172972800 Len: 48048 End: 173020848 SourceOffset: 48048 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 30000/1001 (29.97) Format: MONO Mute: MUTE + └── Clip (1): Start: 172972800 Len: 48048 End: 173020848 SourceOffset: 48048 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + diff --git a/test/expected/PR_AIFF_Internal.aaf.expected b/test/expected/PR_AIFF_Internal.aaf.expected index 61805e2..fea4252 100644 --- a/test/expected/PR_AIFF_Internal.aaf.expected +++ b/test/expected/PR_AIFF_Internal.aaf.expected @@ -39,17 +39,21 @@ Media Essences : ================ - 0: Type: AIFC Length: 0 01 Ch - 48000 Hz - 16 bits file: EMBEDDED file_name: 1000hz-18dbs16b44.1k.wav + Audio[1] :: Format: AIFC - 01 ch - 48000 Hz - 16 bits Length: 51260 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "EMBEDDED" + └── Metadata: + - Name: "Take" Text: "" + - Name: "Scene" Text: "" Tracks & Clips : ================ -VideoTrack (1) - edit_rate 30000/1001 (29.97) - "" -Track (1) - MONO - Gain: none - Pan: none - edit_rate: 30000/1001 (29.97) - "Audio 1" - Clip:0 Channel: 1 Gain: +00.0 dB GainAuto: none Start: 172799828 Len: 48048 End: 172847876 SrcOffset: 1601 - SourceFile: [ch all] 1000hz-18dbs16b44.1k.wav (1000hz-18dbs16b44.1k.wav) - + VideoTrack[1] :: EditRate: 30000/1001 (29.97) + AudioTrack[1] :: EditRate: 30000/1001 (29.97) Format: MONO Name: "Audio 1" + └── Clip (1): Start: 172799828 Len: 48048 End: 172847876 SourceOffset: 1601 Channels: 1 Gain: +00.0 dB + └── SourceFile [ch ALL]: "1000hz-18dbs16b44.1k.wav" + diff --git a/test/expected/PR_Audio_Levels-noBTM.aaf.expected b/test/expected/PR_Audio_Levels-noBTM.aaf.expected new file mode 100644 index 0000000..eaeedb9 --- /dev/null +++ b/test/expected/PR_Audio_Levels-noBTM.aaf.expected @@ -0,0 +1,114 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-14 17:23:52.00 + AAF ObjSpec Version : 1.2 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Adobe + ProductName : Premiere Pro + ProductVersion : 23.5.0.0 AAFVersionUnknown (0) + ProductVersionString : 23.5.0 + ProductID : { 0x00000000 0x0000 0x0000 { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 } } + Date : 2024-01-14 17:23:52.00 + ToolkitVersion : 1.2.0.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x632775f4 0xdab5 0x4054 { 0x9e 0xc3 0x23 0x8e 0x87 0x93 0xd0 0x3e } } + + + + Composition Name : PR_Audio_Levels + + TC EditRrate : 25/1 + TC FPS : 25 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 273 (EditRate: 25/1) + Composition End (samples) : 240786 + Composition End : 00:00:10:23 + + Dominant Sample Rate : 22050 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 0 Name: "stereo-identif.wav" UniqueName: "stereo-identif.wav_1" + ├── File: "file://si.francetv.fr/process_limo/SDG/Utilisateurs/Adrien%20GESTA-FLINE/prjcts_prs/libaaf/fullres/stereo-identif.wav" + └── Metadata: + - Name: "Take" Text: "" + - Name: "Scene" Text: "" + + Audio[2] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 0 Name: "stereo-identif.wav" UniqueName: "stereo-identif.wav" + ├── File: "file://si.francetv.fr/process_limo/SDG/Utilisateurs/Adrien%20GESTA-FLINE/prjcts_prs/libaaf/fullres/stereo-identif.wav" + └── Metadata: + - Name: "Take" Text: "" + - Name: "Scene" Text: "" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 0 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file://si.francetv.fr/process_limo/SDG/Utilisateurs/Adrien%20GESTA-FLINE/prjcts_prs/libaaf/res/1000hz-18dbs16b44.1k.wav" + └── Metadata: + - Name: "Take" Text: "" + - Name: "Scene" Text: "" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 25/1 (25.00) + + + AudioTrack[1] :: EditRate: 25/1 (25.00) Format: MONO Name: "Audio 1" + ├── Clip (1): Start: 0 Len: 42336 End: 42336 SourceOffset: 0 Channels: 1 Gain: +00.0 dB + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + ├── Clip (2): Start: 66150 Len: 42336 End: 108486 SourceOffset: 0 Channels: 1 Gain: +06.0 dB + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + ├── Clip (3): Start: 132300 Len: 42336 End: 174636 SourceOffset: 0 Channels: 1 Gain: +06.0 dB + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + └── Clip (4): Start: 198450 Len: 42336 End: 240786 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + ├── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + └── Clip Volume Automation ────────────────────── + _time: 0.062500 _value: 1.000000 (+00.0 dB) + _time: 0.187500 _value: 0.021242 (-33.5 dB) + _time: 0.312500 _value: 3.438090 (+10.7 dB) + _time: 0.479167 _value: 0.021242 (-33.5 dB) + _time: 0.625000 _value: 3.438090 (+10.7 dB) + _time: 0.791667 _value: 0.010876 (-39.3 dB) + _time: 0.916667 _value: 1.000000 (+00.0 dB) + + + AudioTrack[2] :: EditRate: 25/1 (25.00) Format: STEREO Name: "Audio 2" + ├── Clip (1): Start: 0 Len: 42336 End: 42336 SourceOffset: 0 Channels: 2 Gain: +00.0 dB + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + ├── Clip (2): Start: 66150 Len: 42336 End: 108486 SourceOffset: 0 Channels: 2 Gain: +06.0 dB + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + ├── Clip (3): Start: 132300 Len: 42336 End: 174636 SourceOffset: 0 Channels: 2 Gain: +06.0 dB + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + └── Clip (4): Start: 198450 Len: 42336 End: 240786 SourceOffset: 0 Channels: 2 VolumeAutomation: YES + ├── SourceFile [ch 1]: "stereo-identif.wav" + ├── SourceFile [ch 2]: "stereo-identif.wav_1" + └── Clip Volume Automation ────────────────────── + _time: 0.041667 _value: 1.425267 (+03.1 dB) + _time: 0.166667 _value: 0.016402 (-35.7 dB) + _time: 0.333333 _value: 5.280234 (+14.5 dB) + _time: 0.500000 _value: 0.032006 (-29.9 dB) + _time: 0.666667 _value: 4.652070 (+13.4 dB) + _time: 0.812500 _value: 0.020971 (-33.6 dB) + _time: 0.916667 _value: 1.425267 (+03.1 dB) + + diff --git a/test/expected/PR_Audio_Pan-noBTM.aaf.expected b/test/expected/PR_Audio_Pan-noBTM.aaf.expected new file mode 100644 index 0000000..19d6911 --- /dev/null +++ b/test/expected/PR_Audio_Pan-noBTM.aaf.expected @@ -0,0 +1,91 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-14 17:20:47.00 + AAF ObjSpec Version : 1.2 + ObjectModel Version : 1 + Operational Pattern : AAFOPDef_EditProtocol + + + + CompanyName : Adobe + ProductName : Premiere Pro + ProductVersion : 23.5.0.0 AAFVersionUnknown (0) + ProductVersionString : 23.5.0 + ProductID : { 0x00000000 0x0000 0x0000 { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 } } + Date : 2024-01-14 17:20:47.00 + ToolkitVersion : 1.2.0.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xc601c2f3 0xc254 0x4f2a { 0xa8 0x09 0x3b 0xec 0xde 0x0e 0xee 0x3b } } + + + + Composition Name : PR_Audio_Pan + + TC EditRrate : 25/1 + TC FPS : 25 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 198 (EditRate: 25/1) + Composition End (samples) : 174636 + Composition End : 00:00:07:23 + + Dominant Sample Rate : 22050 + Dominant Sample Size : 16 bits + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 0 Name: "stereo-identif.wav" UniqueName: "stereo-identif.wav_1" + ├── File: "file://si.francetv.fr/process_limo/SDG/Utilisateurs/Adrien%20GESTA-FLINE/prjcts_prs/libaaf/fullres/stereo-identif.wav" + └── Metadata: + - Name: "Take" Text: "" + - Name: "Scene" Text: "" + + Audio[2] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 0 Name: "stereo-identif.wav" UniqueName: "stereo-identif.wav" + ├── File: "file://si.francetv.fr/process_limo/SDG/Utilisateurs/Adrien%20GESTA-FLINE/prjcts_prs/libaaf/fullres/stereo-identif.wav" + └── Metadata: + - Name: "Take" Text: "" + - Name: "Scene" Text: "" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 0 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file://si.francetv.fr/process_limo/SDG/Utilisateurs/Adrien%20GESTA-FLINE/prjcts_prs/libaaf/res/1000hz-18dbs16b44.1k.wav" + └── Metadata: + - Name: "Take" Text: "" + - Name: "Scene" Text: "" + + +Tracks & Clips : +================ + + VideoTrack[1] :: EditRate: 25/1 (25.00) + + + AudioTrack[1] :: EditRate: 25/1 (25.00) Format: MONO Pan: 0.25 Name: "Audio 1" + ├── Clip (1): Start: 0 Len: 42336 End: 42336 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + ├── Clip (2): Start: 66150 Len: 42336 End: 108486 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + └── Clip (3): Start: 132300 Len: 42336 End: 174636 SourceOffset: 0 Channels: 1 Gain: +00.0 dB + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 25/1 (25.00) Format: STEREO Name: "Audio 2" + ├── Clip (1): Start: 0 Len: 42336 End: 42336 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + ├── Clip (2): Start: 66150 Len: 42336 End: 108486 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + └── Clip (3): Start: 132300 Len: 42336 End: 174636 SourceOffset: 0 Channels: 2 + ├── SourceFile [ch 1]: "stereo-identif.wav" + └── SourceFile [ch 2]: "stereo-identif.wav_1" + + diff --git a/test/expected/PR_Fades.aaf.expected b/test/expected/PR_Fades.aaf.expected index 132803d..7a54980 100644 --- a/test/expected/PR_Fades.aaf.expected +++ b/test/expected/PR_Fades.aaf.expected @@ -39,53 +39,93 @@ Media Essences : ================ - 0: Type: WAVE Length: 0 02 Ch - 22050 Hz - 16 bits file: file://si.francetv.fr/process_limo/SDG/Utilisateurs/Adrien%20GESTA-FLINE/prjcts_prs/libaaf/fullres/stereo-identif.wav file_name: stereo-identif.wav - 1: Type: WAVE Length: 0 01 Ch - 44100 Hz - 16 bits file: file://si.francetv.fr/process_limo/SDG/Utilisateurs/Adrien%20GESTA-FLINE/prjcts_prs/libaaf/res/1000hz-18dbs16b44.1k.wav file_name: 1000hz-18dbs16b44.1k.wav + Audio[1] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 0 Name: "stereo-identif.wav" UniqueName: "stereo-identif.wav_1" + ├── File: "file://si.francetv.fr/process_limo/SDG/Utilisateurs/Adrien%20GESTA-FLINE/prjcts_prs/libaaf/fullres/stereo-identif.wav" + └── Metadata: + - Name: "Take" Text: "" + - Name: "Scene" Text: "" + Audio[2] :: Format: WAVE - 02 ch - 22050 Hz - 16 bits Length: 0 Name: "stereo-identif.wav" UniqueName: "stereo-identif.wav" + ├── File: "file://si.francetv.fr/process_limo/SDG/Utilisateurs/Adrien%20GESTA-FLINE/prjcts_prs/libaaf/fullres/stereo-identif.wav" + └── Metadata: + - Name: "Take" Text: "" + - Name: "Scene" Text: "" -Tracks & Clips : -================ - -VideoTrack (1) - edit_rate 30000/1001 (29.97) - "" -Track (1) - MONO - Gain: none - Pan: none - edit_rate: 30000/1001 (29.97) - "Audio 1" - Clip:0 Channel: 1 Gain: +00.0 dB GainAuto: none Start: 0 Len: 19129 End: 19129 SrcOffset: 19864 FadeIn: CURV_LOG (2207) FadeOut: CURV_LOG (2207) - SourceFile: [ch 1] 1000hz-18dbs16b44.1k.wav (1000hz-18dbs16b44.1k.wav) - Clip:1 Channel: 1 Gain: +00.0 dB GainAuto: none Start: 110360 Len: 19129 End: 129489 SrcOffset: 19864 FadeIn: CURV_LIN (2207) FadeOut: CURV_LIN (2207) - SourceFile: [ch 1] 1000hz-18dbs16b44.1k.wav (1000hz-18dbs16b44.1k.wav) - Clip:2 Channel: 1 Gain: +00.0 dB GainAuto: none Start: 220720 Len: 19129 End: 239849 SrcOffset: 19864 FadeIn: CURV_PWR (2207) FadeOut: CURV_PWR (2207) - SourceFile: [ch 1] 1000hz-18dbs16b44.1k.wav (1000hz-18dbs16b44.1k.wav) - Clip:3 Channel: 1 Gain: +00.0 dB GainAuto: none Start: 331080 Len: 22807 End: 353888 SrcOffset: 19864 - SourceFile: [ch 1] 1000hz-18dbs16b44.1k.wav (1000hz-18dbs16b44.1k.wav) - XFade: CURV_LOG (7357) - Clip:4 Channel: 1 Gain: +00.0 dB GainAuto: none Start: 346531 Len: 26486 End: 373017 SrcOffset: 16186 - SourceFile: [ch 1] 1000hz-18dbs16b44.1k.wav (1000hz-18dbs16b44.1k.wav) - XFade: CURV_LIN (8093) - Clip:5 Channel: 1 Gain: +00.0 dB GainAuto: none Start: 364924 Len: 27222 End: 392146 SrcOffset: 15450 - SourceFile: [ch 1] 1000hz-18dbs16b44.1k.wav (1000hz-18dbs16b44.1k.wav) - XFade: CURV_PWR (7357) - Clip:6 Channel: 1 Gain: +00.0 dB GainAuto: none Start: 384789 Len: 22807 End: 407597 SrcOffset: 16186 - SourceFile: [ch 1] 1000hz-18dbs16b44.1k.wav (1000hz-18dbs16b44.1k.wav) - - -Track (2) - STEREO - Gain: none - Pan: none - edit_rate: 30000/1001 (29.97) - "Audio 2" - Clip:7 Channel: 2 Gain: +00.0 dB GainAuto: none Start: 0 Len: 42672 End: 42672 SrcOffset: 0 FadeIn: CURV_LOG (7357) FadeOut: CURV_LOG (7357) - SourceFile: [ch all] stereo-identif.wav (stereo-identif.wav) - Clip:8 Channel: 2 Gain: +00.0 dB GainAuto: none Start: 110360 Len: 42672 End: 153032 SrcOffset: 0 FadeIn: CURV_LIN (7357) FadeOut: CURV_LIN (7357) - SourceFile: [ch all] stereo-identif.wav (stereo-identif.wav) - Clip:9 Channel: 2 Gain: +00.0 dB GainAuto: none Start: 220720 Len: 42672 End: 263393 SrcOffset: 0 FadeIn: CURV_PWR (7357) FadeOut: CURV_PWR (7357) - SourceFile: [ch all] stereo-identif.wav (stereo-identif.wav) - Clip:10 Channel: 2 Gain: +00.0 dB GainAuto: none Start: 331080 Len: 41936 End: 373017 SrcOffset: 0 - SourceFile: [ch all] stereo-identif.wav (stereo-identif.wav) - XFade: CURV_LOG (7357) - Clip:11 Channel: 2 Gain: +00.0 dB GainAuto: none Start: 365660 Len: 41201 End: 406861 SrcOffset: 735 - SourceFile: [ch all] stereo-identif.wav (stereo-identif.wav) - XFade: CURV_LIN (7357) - Clip:12 Channel: 2 Gain: +00.0 dB GainAuto: none Start: 399504 Len: 41201 End: 440705 SrcOffset: 735 - SourceFile: [ch all] stereo-identif.wav (stereo-identif.wav) - XFade: CURV_PWR (7357) - Clip:13 Channel: 2 Gain: +00.0 dB GainAuto: none Start: 433347 Len: 41936 End: 475284 SrcOffset: 735 - SourceFile: [ch all] stereo-identif.wav (stereo-identif.wav) + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 0 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "file://si.francetv.fr/process_limo/SDG/Utilisateurs/Adrien%20GESTA-FLINE/prjcts_prs/libaaf/res/1000hz-18dbs16b44.1k.wav" + └── Metadata: + - Name: "Take" Text: "" + - Name: "Scene" Text: "" +Tracks & Clips : +================ + VideoTrack[1] :: EditRate: 30000/1001 (29.97) + + + AudioTrack[1] :: EditRate: 30000/1001 (29.97) Format: MONO Name: "Audio 1" + ├── Clip (1): Start: 0 Len: 19129 End: 19129 SourceOffset: 19864 Channels: 1 Gain: +00.0 dB FadeIn: CURV_LOG (2207) FadeOut: CURV_LOG (2207) + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + ├── Clip (2): Start: 110360 Len: 19129 End: 129489 SourceOffset: 19864 Channels: 1 Gain: +00.0 dB FadeIn: CURV_LIN (2207) FadeOut: CURV_LIN (2207) + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + ├── Clip (3): Start: 220720 Len: 19129 End: 239849 SourceOffset: 19864 Channels: 1 Gain: +00.0 dB FadeIn: CURV_PWR (2207) FadeOut: CURV_PWR (2207) + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + ├── Clip (4): Start: 331080 Len: 22807 End: 353888 SourceOffset: 19864 Channels: 1 Gain: +00.0 dB + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + ├── X-FADE: CURV_LOG Length: 7357 CutPoint: 3678 + │ + ├── Clip (5): Start: 346531 Len: 26486 End: 373017 SourceOffset: 16186 Channels: 1 Gain: +00.0 dB + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + ├── X-FADE: CURV_LIN Length: 8093 CutPoint: 4414 + │ + ├── Clip (6): Start: 364924 Len: 27222 End: 392146 SourceOffset: 15450 Channels: 1 Gain: +00.0 dB + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + │ + ├── X-FADE: CURV_PWR Length: 7357 CutPoint: 3678 + │ + └── Clip (7): Start: 384789 Len: 22807 End: 407597 SourceOffset: 16186 Channels: 1 Gain: +00.0 dB + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k.wav" + + + AudioTrack[2] :: EditRate: 30000/1001 (29.97) Format: STEREO Name: "Audio 2" + ├── Clip (1): Start: 0 Len: 42672 End: 42672 SourceOffset: 0 Channels: 2 Gain: +00.0 dB FadeIn: CURV_LOG (7357) FadeOut: CURV_LOG (7357) + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + ├── Clip (2): Start: 110360 Len: 42672 End: 153032 SourceOffset: 0 Channels: 2 Gain: +00.0 dB FadeIn: CURV_LIN (7357) FadeOut: CURV_LIN (7357) + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + ├── Clip (3): Start: 220720 Len: 42672 End: 263393 SourceOffset: 0 Channels: 2 Gain: +00.0 dB FadeIn: CURV_PWR (7357) FadeOut: CURV_PWR (7357) + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + ├── Clip (4): Start: 331080 Len: 41936 End: 373017 SourceOffset: 0 Channels: 2 Gain: +00.0 dB + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + ├── X-FADE: CURV_LOG Length: 7357 CutPoint: 3678 + │ + ├── Clip (5): Start: 365660 Len: 41201 End: 406861 SourceOffset: 735 Channels: 2 Gain: +00.0 dB + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + ├── X-FADE: CURV_LIN Length: 7357 CutPoint: 3678 + │ + ├── Clip (6): Start: 399504 Len: 41201 End: 440705 SourceOffset: 735 Channels: 2 Gain: +00.0 dB + │ ├── SourceFile [ch 1]: "stereo-identif.wav" + │ └── SourceFile [ch 2]: "stereo-identif.wav_1" + │ + ├── X-FADE: CURV_PWR Length: 7357 CutPoint: 3678 + │ + └── Clip (7): Start: 433347 Len: 41936 End: 475284 SourceOffset: 735 Channels: 2 Gain: +00.0 dB + ├── SourceFile [ch 1]: "stereo-identif.wav" + └── SourceFile [ch 2]: "stereo-identif.wav_1" + diff --git a/test/expected/PR_WAV_Internal.aaf.expected b/test/expected/PR_WAV_Internal.aaf.expected index 02bdf6c..ae7c976 100644 --- a/test/expected/PR_WAV_Internal.aaf.expected +++ b/test/expected/PR_WAV_Internal.aaf.expected @@ -39,17 +39,21 @@ Media Essences : ================ - 0: Type: WAVE Length: 51252 01 Ch - 48000 Hz - 16 bits file: EMBEDDED file_name: 1000hz-18dbs16b44.1k.wav + Audio[1] :: Format: WAVE - 01 ch - 48000 Hz - 16 bits Length: 51252 Name: "1000hz-18dbs16b44.1k.wav" UniqueName: "1000hz-18dbs16b44.1k.wav" + ├── File: "EMBEDDED" + └── Metadata: + - Name: "Take" Text: "" + - Name: "Scene" Text: "" Tracks & Clips : ================ -VideoTrack (1) - edit_rate 30000/1001 (29.97) - "" -Track (1) - MONO - Gain: none - Pan: none - edit_rate: 30000/1001 (29.97) - "Audio 1" - Clip:0 Channel: 1 Gain: +00.0 dB GainAuto: none Start: 172799828 Len: 48048 End: 172847876 SrcOffset: 1601 - SourceFile: [ch all] 1000hz-18dbs16b44.1k.wav (1000hz-18dbs16b44.1k.wav) - + VideoTrack[1] :: EditRate: 30000/1001 (29.97) + AudioTrack[1] :: EditRate: 30000/1001 (29.97) Format: MONO Name: "Audio 1" + └── Clip (1): Start: 172799828 Len: 48048 End: 172847876 SourceOffset: 1601 Channels: 1 Gain: +00.0 dB + └── SourceFile [ch ALL]: "1000hz-18dbs16b44.1k.wav" + diff --git a/test/expected/PT_AIFF_External.aaf.expected b/test/expected/PT_AIFF_External.aaf.expected index f31b831..6364df7 100644 --- a/test/expected/PT_AIFF_External.aaf.expected +++ b/test/expected/PT_AIFF_External.aaf.expected @@ -35,23 +35,23 @@ Dominant Sample Rate : 44100 Dominant Sample Size : 16 bits - UserComments : - [0] Name: "Comment" Text: "" + Metadata: + - Name: "Comment" Text: "" Media Essences : ================ - 0: Type: AIFC Length: 132304 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.aiff file_name: 1000hz-18dbs16b44.1k-01 + Audio[1] :: Format: AIFC - 01 ch - 44100 Hz - 16 bits Length: 132304 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/res/1000hz-18dbs16b44.1k.aiff" Tracks & Clips : ================ -Track (1) - MONO - Gain: none - Pan: none - edit_rate: 44100/1 (44100.00) - "Audio 1" - Clip:0 Channel: 1 Gain: none GainAuto: none Start: 158804100 Len: 44100 End: 158848200 SrcOffset: 44100 - SourceFile: [ch 1] 1000hz-18dbs16b44.1k-01 (1000hz-18dbs16b44.1k-01) - - + AudioTrack[1] :: EditRate: 44100/1 (44100.00) Format: MONO Name: "Audio 1" + └── Clip (1): Start: 158804100 Len: 44100 End: 158848200 SourceOffset: 44100 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + diff --git a/test/expected/PT_Audio_Levels-noEMCC-noExpTracksAsMultiChannel.aaf.expected b/test/expected/PT_Audio_Levels-noEMCC-noExpTracksAsMultiChannel.aaf.expected new file mode 100644 index 0000000..050559a --- /dev/null +++ b/test/expected/PT_Audio_Levels-noEMCC-noExpTracksAsMultiChannel.aaf.expected @@ -0,0 +1,256 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-10 12:22:55.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-01-10 12:22:51.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x74ba0939 0xe0df 0x4f6a { 0xb6 0x20 0x5c 0x0a 0xc0 0xe5 0x89 0x93 } } + + + + Composition Name : PT_Audio_Gain-noEMCC-noExpTracksAsMultiChannel + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 6747300 (EditRate: 44100/1) + Composition End (samples) : 6747300 + Composition End : 00:02:33:00 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 86234 Name: "stereo-identif-04.R" UniqueName: "stereo-identif-04.R" + └── File: "file:///c%3a/Users/user/localshare/aaf/dumb/PT_Audio_GahzvcXVCWwpszWZFB.wav" + + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 86234 Name: "stereo-identif-04.L" UniqueName: "stereo-identif-04.L" + └── File: "file:///c%3a/Users/user/localshare/aaf/dumb/PT_Audio_GazyrbXVCWygszWZFB.wav" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 132300 Name: "1000hz-18dbs16b44.1k-04" UniqueName: "1000hz-18dbs16b44.1k-04" + └── File: "file:///c%3a/Users/user/localshare/aaf/dumb/PT_Audio_GayrgzWVCWpcszWZFB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 44100/1 (44100.00) Format: MONO Name: "Audio 1" + ├── Clip (1): Start: 0 Len: 132300 End: 132300 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-04" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 0.999992 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ + ├── Clip (2): Start: 1323000 Len: 132300 End: 1455300 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-04" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ + ├── Clip (3): Start: 2646000 Len: 132300 End: 2778300 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-04" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ + ├── Clip (4): Start: 3969000 Len: 132300 End: 4101300 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-04" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 3.935501 (+11.9 dB) + │ _time: 0.122086 _value: 3.981072 (+12.0 dB) + │ _time: 0.226092 _value: 1.000000 (+00.0 dB) + │ _time: 0.338806 _value: 0.010233 (-39.8 dB) + │ _time: 0.439426 _value: 3.981072 (+12.0 dB) + │ _time: 0.571005 _value: 0.012589 (-38.0 dB) + │ _time: 0.694845 _value: 3.273407 (+10.3 dB) + │ _time: 0.859320 _value: 1.000000 (+00.0 dB) + │ _time: 0.981224 _value: 0.053088 (-25.5 dB) + │ _time: 1.000000 _value: 3.548134 (+11.0 dB) + │ _time: 1.000000 _value: 1.995262 (+06.0 dB) + │ + ├── Clip (5): Start: 5292000 Len: 132300 End: 5424300 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-04" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 0.017783 (-35.0 dB) + │ _time: 0.045714 _value: 0.017579 (-35.1 dB) + │ _time: 0.199546 _value: 3.981072 (+12.0 dB) + │ _time: 0.303553 _value: 1.000000 (+00.0 dB) + │ _time: 0.416266 _value: 0.010233 (-39.8 dB) + │ _time: 0.516886 _value: 3.981072 (+12.0 dB) + │ _time: 0.648466 _value: 0.012589 (-38.0 dB) + │ _time: 0.772305 _value: 3.273407 (+10.3 dB) + │ _time: 0.936780 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 0.053703 (-25.4 dB) + │ _time: 1.000000 _value: 0.053088 (-25.5 dB) + │ + └── Clip (6): Start: 6615000 Len: 132300 End: 6747300 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + ├── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-04" + └── Clip Volume Automation ────────────────────── + _time: 0.000000 _value: 1.000000 (+00.0 dB) + _time: 0.023522 _value: 1.000000 (+00.0 dB) + _time: 0.170272 _value: 1.000000 (+00.0 dB) + _time: 0.170280 _value: 1.135011 (+01.1 dB) + _time: 0.179713 _value: 1.000000 (+00.0 dB) + _time: 0.292426 _value: 0.010233 (-39.8 dB) + _time: 0.393046 _value: 3.981072 (+12.0 dB) + _time: 0.524626 _value: 0.012589 (-38.0 dB) + _time: 0.648466 _value: 3.273407 (+10.3 dB) + _time: 0.812940 _value: 1.000000 (+00.0 dB) + _time: 0.822079 _value: 0.812831 (-01.8 dB) + _time: 0.822086 _value: 1.000000 (+00.0 dB) + _time: 0.987143 _value: 1.000000 (+00.0 dB) + _time: 1.000000 _value: 1.000000 (+00.0 dB) + + + AudioTrack[2] :: EditRate: 44100/1 (44100.00) Format: MONO Name: "Audio 2" + ├── Clip (1): Start: 0 Len: 85260 End: 85260 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "stereo-identif-04.L" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 0.999988 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ + ├── Clip (2): Start: 1323000 Len: 85260 End: 1408260 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "stereo-identif-04.L" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ + ├── Clip (3): Start: 2646000 Len: 85260 End: 2731260 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "stereo-identif-04.L" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ + ├── Clip (4): Start: 3969000 Len: 83790 End: 4052790 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "stereo-identif-04.L" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 3.935501 (+11.9 dB) + │ _time: 0.168326 _value: 3.981072 (+12.0 dB) + │ _time: 0.332546 _value: 1.000000 (+00.0 dB) + │ _time: 0.510514 _value: 0.010233 (-39.8 dB) + │ _time: 0.669388 _value: 3.981072 (+12.0 dB) + │ _time: 0.877145 _value: 0.012589 (-38.0 dB) + │ _time: 1.000000 _value: 3.273407 (+10.3 dB) + │ _time: 1.000000 _value: 1.995262 (+06.0 dB) + │ + ├── Clip (5): Start: 5292000 Len: 85260 End: 5377260 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "stereo-identif-04.L" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 0.014638 _value: 1.000000 (+00.0 dB) + │ _time: 0.189538 _value: 0.010233 (-39.8 dB) + │ _time: 0.345672 _value: 3.981072 (+12.0 dB) + │ _time: 0.549848 _value: 0.012589 (-38.0 dB) + │ _time: 0.742013 _value: 3.273407 (+10.3 dB) + │ _time: 0.997232 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 0.053703 (-25.4 dB) + │ _time: 1.000000 _value: 0.053088 (-25.5 dB) + │ + └── Clip (6): Start: 6615000 Len: 85260 End: 6700260 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + ├── SourceFile [ch 1]: "stereo-identif-04.L" + └── Clip Volume Automation ────────────────────── + _time: 0.000000 _value: 1.135011 (+01.1 dB) + _time: 0.014638 _value: 1.000000 (+00.0 dB) + _time: 0.189538 _value: 0.010233 (-39.8 dB) + _time: 0.345672 _value: 3.981072 (+12.0 dB) + _time: 0.549848 _value: 0.012589 (-38.0 dB) + _time: 0.742013 _value: 3.273407 (+10.3 dB) + _time: 0.997232 _value: 1.000000 (+00.0 dB) + _time: 0.999988 _value: 0.954993 (-00.4 dB) + _time: 1.000000 _value: 1.000000 (+00.0 dB) + _time: 1.000000 _value: 1.000000 (+00.0 dB) + + + AudioTrack[3] :: EditRate: 44100/1 (44100.00) Format: MONO Name: "Audio 2" + ├── Clip (1): Start: 0 Len: 85260 End: 85260 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "stereo-identif-04.R" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 0.999988 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ + ├── Clip (2): Start: 1323000 Len: 85260 End: 1408260 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "stereo-identif-04.R" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ + ├── Clip (3): Start: 2646000 Len: 85260 End: 2731260 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "stereo-identif-04.R" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 1.000000 (+00.0 dB) + │ + ├── Clip (4): Start: 3969000 Len: 83790 End: 4052790 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "stereo-identif-04.R" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 3.935501 (+11.9 dB) + │ _time: 0.168326 _value: 3.981072 (+12.0 dB) + │ _time: 0.332546 _value: 1.000000 (+00.0 dB) + │ _time: 0.510514 _value: 0.010233 (-39.8 dB) + │ _time: 0.669388 _value: 3.981072 (+12.0 dB) + │ _time: 0.877145 _value: 0.012589 (-38.0 dB) + │ _time: 1.000000 _value: 3.273407 (+10.3 dB) + │ _time: 1.000000 _value: 1.995262 (+06.0 dB) + │ + ├── Clip (5): Start: 5292000 Len: 85260 End: 5377260 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + │ ├── SourceFile [ch 1]: "stereo-identif-04.R" + │ └── Clip Volume Automation ────────────────────── + │ _time: 0.000000 _value: 1.000000 (+00.0 dB) + │ _time: 0.014638 _value: 1.000000 (+00.0 dB) + │ _time: 0.189538 _value: 0.010233 (-39.8 dB) + │ _time: 0.345672 _value: 3.981072 (+12.0 dB) + │ _time: 0.549848 _value: 0.012589 (-38.0 dB) + │ _time: 0.742013 _value: 3.273407 (+10.3 dB) + │ _time: 0.997232 _value: 1.000000 (+00.0 dB) + │ _time: 1.000000 _value: 0.053703 (-25.4 dB) + │ _time: 1.000000 _value: 0.053088 (-25.5 dB) + │ + └── Clip (6): Start: 6615000 Len: 85260 End: 6700260 SourceOffset: 0 Channels: 1 VolumeAutomation: YES + ├── SourceFile [ch 1]: "stereo-identif-04.R" + └── Clip Volume Automation ────────────────────── + _time: 0.000000 _value: 1.135011 (+01.1 dB) + _time: 0.014638 _value: 1.000000 (+00.0 dB) + _time: 0.189538 _value: 0.010233 (-39.8 dB) + _time: 0.345672 _value: 3.981072 (+12.0 dB) + _time: 0.549848 _value: 0.012589 (-38.0 dB) + _time: 0.742013 _value: 3.273407 (+10.3 dB) + _time: 0.997232 _value: 1.000000 (+00.0 dB) + _time: 0.999988 _value: 0.954993 (-00.4 dB) + _time: 1.000000 _value: 1.000000 (+00.0 dB) + _time: 1.000000 _value: 1.000000 (+00.0 dB) + + diff --git a/test/expected/PT_Fades.aaf.expected b/test/expected/PT_Fades.aaf.expected new file mode 100644 index 0000000..be494ea --- /dev/null +++ b/test/expected/PT_Fades.aaf.expected @@ -0,0 +1,229 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-31 00:50:07.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-01-31 00:50:03.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x9ddb35dd 0x8d16 0x40a7 { 0x84 0x6c 0x63 0x47 0x20 0xca 0xdb 0x94 } } + + + + Composition Name : PT_Fades + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 1027 (EditRate: 30/1) + Composition End (samples) : 1509690 + Composition End : 00:00:34:07 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_17" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesrcpqJBHJzpzbJCBB.wav" + + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_16" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvpwvHBHJqpxbJCBB.wav" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 17641 Name: "Fade " UniqueName: "Fade _8" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesmchpJBHJchzbJCBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 17641 Name: "Fade " UniqueName: "Fade _7" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeszwrsHBHJqgxbJCBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_15" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesgycmJBHJbdzbJCBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_14" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeshrprHBHJscxbJCBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 74971 Name: "stereo-identif-03.R" UniqueName: "stereo-identif-03.R" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesgrzgJBHJczybJCBB.wav" + + Audio[8] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 74971 Name: "stereo-identif-03.L" UniqueName: "stereo-identif-03.L" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeswzgqHBHJsywbJCBB.wav" + + Audio[9] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_13" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvhwfJBHJbwybJCBB.wav" + + Audio[10] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_12" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeswvcpHBHJrvwbJCBB.wav" + + Audio[11] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 33811 Name: "Fade " UniqueName: "Fade _6" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvfsdJBHJcrybJCBB.wav" + + Audio[12] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 33811 Name: "Fade " UniqueName: "Fade _5" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesgvyhHBHJqqwbJCBB.wav" + + Audio[13] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_11" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesycqcJBHJfmybJCBB.wav" + + Audio[14] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_10" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvgwgHBHJrhwbJCBB.wav" + + Audio[15] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 72031 Name: "stereo-identif-01.R" UniqueName: "stereo-identif-01.R" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesdgmbJBHJhfybJCBB.wav" + + Audio[16] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 72031 Name: "stereo-identif-01.L" UniqueName: "stereo-identif-01.L" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesxmrfHBHJrdwbJCBB.wav" + + Audio[17] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_9" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvffzHBHJgbybJCBB.wav" + + Audio[18] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_8" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadespbpdHBHJszvbJCBB.wav" + + Audio[19] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "Fade " UniqueName: "Fade _4" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadespfcyHBHJmxxbJCBB.wav" + + Audio[20] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "Fade " UniqueName: "Fade _3" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadescqgcHBHJswvbJCBB.wav" + + Audio[21] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_7" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesswywHBHJpsxbJCBB.wav" + + Audio[22] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_6" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadescpdbHBHJwrvbJCBB.wav" + + Audio[23] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_5" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeszwzyFBHJwmvbJCBB.wav" + + Audio[24] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 20581 Name: "Fade " UniqueName: "Fade _2" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadescyxxFBHJyfvbJCBB.wav" + + Audio[25] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_4" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesdcvwFBHJybvbJCBB.wav" + + Audio[26] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 133771 Name: "1000hz-18dbs16b44.1k" UniqueName: "1000hz-18dbs16b44.1k" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesbzqvFBHJbysbJCBB.wav" + + Audio[27] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_3" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesqmmsFBHJbvsbJCBB.wav" + + Audio[28] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 32341 Name: "Fade " UniqueName: "Fade _1" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesmmgrFBHJdqsbJCBB.wav" + + Audio[29] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_2" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesqvcqFBHJfhsbJCBB.wav" + + Audio[30] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 126421 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadespszmFBHJgdsbJCBB.wav" + + Audio[31] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_1" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadespwwhFBHJgzrbJCBB.wav" + + Audio[32] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 22051 Name: "Fade " UniqueName: "Fade " + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesdfsgFBHJgwrbJCBB.wav" + + Audio[33] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesppgfFBHJxqrbJCBB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO Name: "Audio 1" + ├── Clip (1): Start: 1295070 Len: 1470 End: 1296540 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "Sample accurate edit" + │ + ├── Clip (2): Start: 1296540 Len: 19110 End: 1315650 SourceOffset: 1470 Channels: 1 + │ └── SourceFile [ch 1]: "Fade " + │ + ├── Clip (3): Start: 1315650 Len: 1470 End: 1317120 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "Sample accurate edit_1" + │ + ├── Clip (4): Start: 1317120 Len: 58800 End: 1375920 SourceOffset: 22050 Channels: 1 + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + │ + ├── Clip (5): Start: 1375920 Len: 1470 End: 1377390 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "Sample accurate edit_2" + │ + ├── Clip (6): Start: 1377390 Len: 29400 End: 1406790 SourceOffset: 1470 Channels: 1 + │ └── SourceFile [ch 1]: "Fade _1" + │ + ├── Clip (7): Start: 1406790 Len: 1470 End: 1408260 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "Sample accurate edit_3" + │ + ├── Clip (8): Start: 1408260 Len: 80850 End: 1489110 SourceOffset: 32340 Channels: 1 + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k" + │ + ├── Clip (9): Start: 1489110 Len: 1470 End: 1490580 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "Sample accurate edit_4" + │ + ├── Clip (10): Start: 1490580 Len: 17640 End: 1508220 SourceOffset: 1470 Channels: 1 + │ └── SourceFile [ch 1]: "Fade _2" + │ + └── Clip (11): Start: 1508220 Len: 1470 End: 1509690 SourceOffset: 0 Channels: 1 + └── SourceFile [ch 1]: "Sample accurate edit_5" + + + AudioTrack[2] :: EditRate: 30/1 (30.00) Format: STEREO Name: "Audio 2" + ├── Clip (1): Start: 1347990 Len: 1470 End: 1349460 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "Sample accurate edit_6" + │ └── SourceFile [ch 1]: "Sample accurate edit_7" + │ + ├── Clip (2): Start: 1349460 Len: 13230 End: 1362690 SourceOffset: 1470 Channels: 2 + │ ├── SourceFile [ch 1]: "Fade _3" + │ └── SourceFile [ch 1]: "Fade _4" + │ + ├── Clip (3): Start: 1362690 Len: 1470 End: 1364160 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "Sample accurate edit_8" + │ └── SourceFile [ch 1]: "Sample accurate edit_9" + │ + ├── Clip (4): Start: 1364160 Len: 10290 End: 1374450 SourceOffset: 16170 Channels: 2 + │ ├── SourceFile [ch 1]: "stereo-identif-01.L" + │ └── SourceFile [ch 1]: "stereo-identif-01.R" + │ + ├── Clip (5): Start: 1374450 Len: 1470 End: 1375920 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "Sample accurate edit_10" + │ └── SourceFile [ch 1]: "Sample accurate edit_11" + │ + ├── Clip (6): Start: 1375920 Len: 30870 End: 1406790 SourceOffset: 1470 Channels: 2 + │ ├── SourceFile [ch 1]: "Fade _5" + │ └── SourceFile [ch 1]: "Fade _6" + │ + ├── Clip (7): Start: 1406790 Len: 1470 End: 1408260 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "Sample accurate edit_12" + │ └── SourceFile [ch 1]: "Sample accurate edit_13" + │ + ├── Clip (8): Start: 1408260 Len: 11760 End: 1420020 SourceOffset: 45570 Channels: 2 + │ ├── SourceFile [ch 1]: "stereo-identif-03.L" + │ └── SourceFile [ch 1]: "stereo-identif-03.R" + │ + ├── Clip (9): Start: 1420020 Len: 1470 End: 1421490 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "Sample accurate edit_14" + │ └── SourceFile [ch 1]: "Sample accurate edit_15" + │ + ├── Clip (10): Start: 1421490 Len: 14700 End: 1436190 SourceOffset: 1470 Channels: 2 + │ ├── SourceFile [ch 1]: "Fade _7" + │ └── SourceFile [ch 1]: "Fade _8" + │ + └── Clip (11): Start: 1436190 Len: 1470 End: 1437660 SourceOffset: 0 Channels: 2 + ├── SourceFile [ch 1]: "Sample accurate edit_16" + └── SourceFile [ch 1]: "Sample accurate edit_17" + + diff --git a/test/expected/PT_Fades_A.aaf.expected b/test/expected/PT_Fades_A.aaf.expected new file mode 100644 index 0000000..0689f7a --- /dev/null +++ b/test/expected/PT_Fades_A.aaf.expected @@ -0,0 +1,187 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-31 00:50:07.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-01-31 00:50:03.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x9ddb35dd 0x8d16 0x40a7 { 0x84 0x6c 0x63 0x47 0x20 0xca 0xdb 0x94 } } + + + + Composition Name : PT_Fades + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 1027 (EditRate: 30/1) + Composition End (samples) : 1509690 + Composition End : 00:00:34:07 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_17" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesrcpqJBHJzpzbJCBB.wav" + + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_16" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvpwvHBHJqpxbJCBB.wav" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 17641 Name: "Fade " UniqueName: "Fade _8" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesmchpJBHJchzbJCBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 17641 Name: "Fade " UniqueName: "Fade _7" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeszwrsHBHJqgxbJCBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_15" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesgycmJBHJbdzbJCBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_14" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeshrprHBHJscxbJCBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 74971 Name: "stereo-identif-03.R" UniqueName: "stereo-identif-03.R" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesgrzgJBHJczybJCBB.wav" + + Audio[8] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 74971 Name: "stereo-identif-03.L" UniqueName: "stereo-identif-03.L" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeswzgqHBHJsywbJCBB.wav" + + Audio[9] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_13" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvhwfJBHJbwybJCBB.wav" + + Audio[10] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_12" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeswvcpHBHJrvwbJCBB.wav" + + Audio[11] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 33811 Name: "Fade " UniqueName: "Fade _6" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvfsdJBHJcrybJCBB.wav" + + Audio[12] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 33811 Name: "Fade " UniqueName: "Fade _5" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesgvyhHBHJqqwbJCBB.wav" + + Audio[13] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_11" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesycqcJBHJfmybJCBB.wav" + + Audio[14] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_10" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvgwgHBHJrhwbJCBB.wav" + + Audio[15] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 72031 Name: "stereo-identif-01.R" UniqueName: "stereo-identif-01.R" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesdgmbJBHJhfybJCBB.wav" + + Audio[16] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 72031 Name: "stereo-identif-01.L" UniqueName: "stereo-identif-01.L" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesxmrfHBHJrdwbJCBB.wav" + + Audio[17] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_9" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvffzHBHJgbybJCBB.wav" + + Audio[18] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_8" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadespbpdHBHJszvbJCBB.wav" + + Audio[19] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "Fade " UniqueName: "Fade _4" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadespfcyHBHJmxxbJCBB.wav" + + Audio[20] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "Fade " UniqueName: "Fade _3" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadescqgcHBHJswvbJCBB.wav" + + Audio[21] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_7" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesswywHBHJpsxbJCBB.wav" + + Audio[22] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_6" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadescpdbHBHJwrvbJCBB.wav" + + Audio[23] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_5" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeszwzyFBHJwmvbJCBB.wav" + + Audio[24] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 20581 Name: "Fade " UniqueName: "Fade _2" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadescyxxFBHJyfvbJCBB.wav" + + Audio[25] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_4" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesdcvwFBHJybvbJCBB.wav" + + Audio[26] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 133771 Name: "1000hz-18dbs16b44.1k" UniqueName: "1000hz-18dbs16b44.1k" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesbzqvFBHJbysbJCBB.wav" + + Audio[27] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_3" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesqmmsFBHJbvsbJCBB.wav" + + Audio[28] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 32341 Name: "Fade " UniqueName: "Fade _1" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesmmgrFBHJdqsbJCBB.wav" + + Audio[29] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_2" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesqvcqFBHJfhsbJCBB.wav" + + Audio[30] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 126421 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadespszmFBHJgdsbJCBB.wav" + + Audio[31] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_1" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadespwwhFBHJgzrbJCBB.wav" + + Audio[32] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 22051 Name: "Fade " UniqueName: "Fade " + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesdfsgFBHJgwrbJCBB.wav" + + Audio[33] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesppgfFBHJxqrbJCBB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO Name: "Audio 1" + ├── Clip (1): Start: 1295070 Len: 22050 End: 1317120 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "Fade " + │ + ├── Clip (2): Start: 1317120 Len: 60270 End: 1377390 SourceOffset: 22050 Channels: 1 + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + │ + ├── Clip (3): Start: 1377390 Len: 30870 End: 1408260 SourceOffset: 1470 Channels: 1 + │ └── SourceFile [ch 1]: "Fade _1" + │ + ├── Clip (4): Start: 1408260 Len: 82320 End: 1490580 SourceOffset: 32340 Channels: 1 + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k" + │ + └── Clip (5): Start: 1490580 Len: 19110 End: 1509690 SourceOffset: 1470 Channels: 1 + └── SourceFile [ch 1]: "Fade _2" + + + AudioTrack[2] :: EditRate: 30/1 (30.00) Format: STEREO Name: "Audio 2" + ├── Clip (1): Start: 1347990 Len: 16170 End: 1364160 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "Fade _3" + │ └── SourceFile [ch 1]: "Fade _4" + │ + ├── Clip (2): Start: 1364160 Len: 11760 End: 1375920 SourceOffset: 16170 Channels: 2 + │ ├── SourceFile [ch 1]: "stereo-identif-01.L" + │ └── SourceFile [ch 1]: "stereo-identif-01.R" + │ + ├── Clip (3): Start: 1375920 Len: 32340 End: 1408260 SourceOffset: 1470 Channels: 2 + │ ├── SourceFile [ch 1]: "Fade _5" + │ └── SourceFile [ch 1]: "Fade _6" + │ + ├── Clip (4): Start: 1408260 Len: 13230 End: 1421490 SourceOffset: 45570 Channels: 2 + │ ├── SourceFile [ch 1]: "stereo-identif-03.L" + │ └── SourceFile [ch 1]: "stereo-identif-03.R" + │ + └── Clip (5): Start: 1421490 Len: 16170 End: 1437660 SourceOffset: 1470 Channels: 2 + ├── SourceFile [ch 1]: "Fade _7" + └── SourceFile [ch 1]: "Fade _8" + + diff --git a/test/expected/PT_Fades_B.aaf.expected b/test/expected/PT_Fades_B.aaf.expected new file mode 100644 index 0000000..705cb31 --- /dev/null +++ b/test/expected/PT_Fades_B.aaf.expected @@ -0,0 +1,170 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-31 00:50:07.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-01-31 00:50:03.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x9ddb35dd 0x8d16 0x40a7 { 0x84 0x6c 0x63 0x47 0x20 0xca 0xdb 0x94 } } + + + + Composition Name : PT_Fades + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 1027 (EditRate: 30/1) + Composition End (samples) : 1509690 + Composition End : 00:00:34:07 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_17" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesrcpqJBHJzpzbJCBB.wav" + + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_16" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvpwvHBHJqpxbJCBB.wav" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 17641 Name: "Fade " UniqueName: "Fade _8" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesmchpJBHJchzbJCBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 17641 Name: "Fade " UniqueName: "Fade _7" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeszwrsHBHJqgxbJCBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_15" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesgycmJBHJbdzbJCBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_14" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeshrprHBHJscxbJCBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 74971 Name: "stereo-identif-03.R" UniqueName: "stereo-identif-03.R" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesgrzgJBHJczybJCBB.wav" + + Audio[8] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 74971 Name: "stereo-identif-03.L" UniqueName: "stereo-identif-03.L" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeswzgqHBHJsywbJCBB.wav" + + Audio[9] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_13" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvhwfJBHJbwybJCBB.wav" + + Audio[10] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_12" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeswvcpHBHJrvwbJCBB.wav" + + Audio[11] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 33811 Name: "Fade " UniqueName: "Fade _6" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvfsdJBHJcrybJCBB.wav" + + Audio[12] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 33811 Name: "Fade " UniqueName: "Fade _5" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesgvyhHBHJqqwbJCBB.wav" + + Audio[13] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_11" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesycqcJBHJfmybJCBB.wav" + + Audio[14] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_10" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvgwgHBHJrhwbJCBB.wav" + + Audio[15] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 72031 Name: "stereo-identif-01.R" UniqueName: "stereo-identif-01.R" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesdgmbJBHJhfybJCBB.wav" + + Audio[16] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 72031 Name: "stereo-identif-01.L" UniqueName: "stereo-identif-01.L" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesxmrfHBHJrdwbJCBB.wav" + + Audio[17] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_9" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvffzHBHJgbybJCBB.wav" + + Audio[18] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_8" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadespbpdHBHJszvbJCBB.wav" + + Audio[19] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "Fade " UniqueName: "Fade _4" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadespfcyHBHJmxxbJCBB.wav" + + Audio[20] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "Fade " UniqueName: "Fade _3" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadescqgcHBHJswvbJCBB.wav" + + Audio[21] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_7" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesswywHBHJpsxbJCBB.wav" + + Audio[22] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_6" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadescpdbHBHJwrvbJCBB.wav" + + Audio[23] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_5" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeszwzyFBHJwmvbJCBB.wav" + + Audio[24] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 20581 Name: "Fade " UniqueName: "Fade _2" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadescyxxFBHJyfvbJCBB.wav" + + Audio[25] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_4" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesdcvwFBHJybvbJCBB.wav" + + Audio[26] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 133771 Name: "1000hz-18dbs16b44.1k" UniqueName: "1000hz-18dbs16b44.1k" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesbzqvFBHJbysbJCBB.wav" + + Audio[27] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_3" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesqmmsFBHJbvsbJCBB.wav" + + Audio[28] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 32341 Name: "Fade " UniqueName: "Fade _1" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesmmgrFBHJdqsbJCBB.wav" + + Audio[29] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_2" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesqvcqFBHJfhsbJCBB.wav" + + Audio[30] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 126421 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadespszmFBHJgdsbJCBB.wav" + + Audio[31] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_1" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadespwwhFBHJgzrbJCBB.wav" + + Audio[32] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 22051 Name: "Fade " UniqueName: "Fade " + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesdfsgFBHJgwrbJCBB.wav" + + Audio[33] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesppgfFBHJxqrbJCBB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO Name: "Audio 1" + ├── Clip (1): Start: 1295070 Len: 113190 End: 1408260 SourceOffset: 0 Channels: 1 FadeIn: CURV_LIN (22050) + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + │ + ├── X-FADE: CURV_LIN Length: 30870 CutPoint: 14700 + │ + └── Clip (2): Start: 1377390 Len: 132300 End: 1509690 SourceOffset: 1470 Channels: 1 FadeOut: CURV_LIN (19110) + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k" + + + AudioTrack[2] :: EditRate: 30/1 (30.00) Format: STEREO Name: "Audio 2" + ├── Clip (1): Start: 1347990 Len: 60270 End: 1408260 SourceOffset: 0 Channels: 2 FadeIn: CURV_LIN (16170) + │ ├── SourceFile [ch 1]: "stereo-identif-01.L" + │ └── SourceFile [ch 1]: "stereo-identif-01.R" + │ + ├── X-FADE: CURV_LIN Length: 32340 CutPoint: 16170 + │ + └── Clip (2): Start: 1375920 Len: 61740 End: 1437660 SourceOffset: 13230 Channels: 2 FadeOut: CURV_LIN (16170) + ├── SourceFile [ch 1]: "stereo-identif-03.L" + └── SourceFile [ch 1]: "stereo-identif-03.R" + + diff --git a/test/expected/PT_Fades_no_handles.aaf.expected b/test/expected/PT_Fades_no_handles.aaf.expected new file mode 100644 index 0000000..456e34a --- /dev/null +++ b/test/expected/PT_Fades_no_handles.aaf.expected @@ -0,0 +1,229 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-31 00:40:18.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-01-31 00:40:12.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x594bf1de 0x1223 0x43a7 { 0xba 0x5c 0xa3 0xd6 0x7a 0xd6 0xfe 0xc3 } } + + + + Composition Name : PT_Fades + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 1027 (EditRate: 30/1) + Composition End (samples) : 1509690 + Composition End : 00:00:34:07 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_17" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadespqbyCRZHfzdcVBBB.wav" + + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_16" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeshffcCRZHmybcVBBB.wav" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 17641 Name: "Fade " UniqueName: "Fade _8" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesdmywCRZHhwdcVBBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 17641 Name: "Fade " UniqueName: "Fade _7" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvqbbCRZHmvbcVBBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_15" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesmpvvCRZHgrdcVBBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_14" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvpyyBRZHqqbcVBBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 14701 Name: "stereo-identif-03.R" UniqueName: "stereo-identif-03.R" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesgxqsCRZHhmdcVBBB.wav" + + Audio[8] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 14701 Name: "stereo-identif-03.L" UniqueName: "stereo-identif-03.L" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesfcwxBRZHrhbcVBBB.wav" + + Audio[9] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_13" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeswhmrCRZHhfdcVBBB.wav" + + Audio[10] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_12" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesqhrwBRZHrdbcVBBB.wav" + + Audio[11] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 33811 Name: "Fade " UniqueName: "Fade _6" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeszbgqCRZHpbdcVBBB.wav" + + Audio[12] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 33811 Name: "Fade " UniqueName: "Fade _5" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeswhmvBRZHqzzbVBBB.wav" + + Audio[13] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_11" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeszmcpCRZHpxccVBBB.wav" + + Audio[14] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_10" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvxfsBRZHrwzbVBBB.wav" + + Audio[15] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 13231 Name: "stereo-identif-01.R" UniqueName: "stereo-identif-01.R" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesxhyhCRZHmsccVBBB.wav" + + Audio[16] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 13231 Name: "stereo-identif-01.L" UniqueName: "stereo-identif-01.L" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesvhcrBRZHrrzbVBBB.wav" + + Audio[17] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_9" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesqbvgCRZHhpccVBBB.wav" + + Audio[18] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_8" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesspzpBRZHvmzbVBBB.wav" + + Audio[19] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "Fade " UniqueName: "Fade _4" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesydqfCRZHggccVBBB.wav" + + Audio[20] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "Fade " UniqueName: "Fade _3" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesyhxmBRZHxfzbVBBB.wav" + + Audio[21] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_7" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesyvhdCRZHhcccVBBB.wav" + + Audio[22] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_6" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesrgvhBRZHzbzbVBBB.wav" + + Audio[23] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_5" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesdfrgBRZHcyybVBBB.wav" + + Audio[24] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 20581 Name: "Fade " UniqueName: "Fade _2" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeszqpfBRZHfvybVBBB.wav" + + Audio[25] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_4" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeshqhdBRZHhqybVBBB.wav" + + Audio[26] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 83791 Name: "1000hz-18dbs16b44.1k" UniqueName: "1000hz-18dbs16b44.1k" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeshpfcBRZHphybVBBB.wav" + + Audio[27] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_3" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesfdcbBRZHqdybVBBB.wav" + + Audio[28] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 32341 Name: "Fade " UniqueName: "Fade _1" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesqpyyZQZHqzxbVBBB.wav" + + Audio[29] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_2" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeszwvxZQZHqwxbVBBB.wav" + + Audio[30] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 61741 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesffrwZQZHrrxbVBBB.wav" + + Audio[31] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_1" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadescsmvZQZHrmxbVBBB.wav" + + Audio[32] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 22051 Name: "Fade " UniqueName: "Fade " + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadesxqgsZQZHvfxbVBBB.wav" + + Audio[33] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit" + └── File: "file:///c%3a/Users/user/localshare/aaf/PT_FadeszfxqZQZHzzwbVBBB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO Name: "Audio 1" + ├── Clip (1): Start: 1295070 Len: 1470 End: 1296540 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "Sample accurate edit" + │ + ├── Clip (2): Start: 1296540 Len: 19110 End: 1315650 SourceOffset: 1470 Channels: 1 + │ └── SourceFile [ch 1]: "Fade " + │ + ├── Clip (3): Start: 1315650 Len: 1470 End: 1317120 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "Sample accurate edit_1" + │ + ├── Clip (4): Start: 1317120 Len: 58800 End: 1375920 SourceOffset: 1470 Channels: 1 + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + │ + ├── Clip (5): Start: 1375920 Len: 1470 End: 1377390 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "Sample accurate edit_2" + │ + ├── Clip (6): Start: 1377390 Len: 29400 End: 1406790 SourceOffset: 1470 Channels: 1 + │ └── SourceFile [ch 1]: "Fade _1" + │ + ├── Clip (7): Start: 1406790 Len: 1470 End: 1408260 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "Sample accurate edit_3" + │ + ├── Clip (8): Start: 1408260 Len: 80850 End: 1489110 SourceOffset: 1470 Channels: 1 + │ └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k" + │ + ├── Clip (9): Start: 1489110 Len: 1470 End: 1490580 SourceOffset: 0 Channels: 1 + │ └── SourceFile [ch 1]: "Sample accurate edit_4" + │ + ├── Clip (10): Start: 1490580 Len: 17640 End: 1508220 SourceOffset: 1470 Channels: 1 + │ └── SourceFile [ch 1]: "Fade _2" + │ + └── Clip (11): Start: 1508220 Len: 1470 End: 1509690 SourceOffset: 0 Channels: 1 + └── SourceFile [ch 1]: "Sample accurate edit_5" + + + AudioTrack[2] :: EditRate: 30/1 (30.00) Format: STEREO Name: "Audio 2" + ├── Clip (1): Start: 1347990 Len: 1470 End: 1349460 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "Sample accurate edit_6" + │ └── SourceFile [ch 1]: "Sample accurate edit_7" + │ + ├── Clip (2): Start: 1349460 Len: 13230 End: 1362690 SourceOffset: 1470 Channels: 2 + │ ├── SourceFile [ch 1]: "Fade _3" + │ └── SourceFile [ch 1]: "Fade _4" + │ + ├── Clip (3): Start: 1362690 Len: 1470 End: 1364160 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "Sample accurate edit_8" + │ └── SourceFile [ch 1]: "Sample accurate edit_9" + │ + ├── Clip (4): Start: 1364160 Len: 10290 End: 1374450 SourceOffset: 1470 Channels: 2 + │ ├── SourceFile [ch 1]: "stereo-identif-01.L" + │ └── SourceFile [ch 1]: "stereo-identif-01.R" + │ + ├── Clip (5): Start: 1374450 Len: 1470 End: 1375920 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "Sample accurate edit_10" + │ └── SourceFile [ch 1]: "Sample accurate edit_11" + │ + ├── Clip (6): Start: 1375920 Len: 30870 End: 1406790 SourceOffset: 1470 Channels: 2 + │ ├── SourceFile [ch 1]: "Fade _5" + │ └── SourceFile [ch 1]: "Fade _6" + │ + ├── Clip (7): Start: 1406790 Len: 1470 End: 1408260 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "Sample accurate edit_12" + │ └── SourceFile [ch 1]: "Sample accurate edit_13" + │ + ├── Clip (8): Start: 1408260 Len: 11760 End: 1420020 SourceOffset: 1470 Channels: 2 + │ ├── SourceFile [ch 1]: "stereo-identif-03.L" + │ └── SourceFile [ch 1]: "stereo-identif-03.R" + │ + ├── Clip (9): Start: 1420020 Len: 1470 End: 1421490 SourceOffset: 0 Channels: 2 + │ ├── SourceFile [ch 1]: "Sample accurate edit_14" + │ └── SourceFile [ch 1]: "Sample accurate edit_15" + │ + ├── Clip (10): Start: 1421490 Len: 14700 End: 1436190 SourceOffset: 1470 Channels: 2 + │ ├── SourceFile [ch 1]: "Fade _7" + │ └── SourceFile [ch 1]: "Fade _8" + │ + └── Clip (11): Start: 1436190 Len: 1470 End: 1437660 SourceOffset: 0 Channels: 2 + ├── SourceFile [ch 1]: "Sample accurate edit_16" + └── SourceFile [ch 1]: "Sample accurate edit_17" + + diff --git a/test/expected/PT_MXF_External.aaf.expected b/test/expected/PT_MXF_External.aaf.expected index d5a8dc6..37c3a08 100644 --- a/test/expected/PT_MXF_External.aaf.expected +++ b/test/expected/PT_MXF_External.aaf.expected @@ -35,23 +35,23 @@ Dominant Sample Rate : 44100 Dominant Sample Size : 16 bits - UserComments : - [0] Name: "Comment" Text: "" + Metadata: + - Name: "Comment" Text: "" Media Essences : ================ - 0: Type: PCM Length: 132301 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_MXF_ExtezdxyVYMTxgrsWRHR.mxf file_name: PT_MXF_ExtepwwsVYMTxgrsYBFR-01 + Audio[1] :: Format: PCM - 01 ch - 44100 Hz - 16 bits Length: 132301 Name: "PT_MXF_ExtepwwsVYMTxgrsYBFR-01" UniqueName: "PT_MXF_ExtepwwsVYMTxgrsYBFR-01" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_MXF_ExtezdxyVYMTxgrsWRHR.mxf" Tracks & Clips : ================ -Track (1) - MONO - Gain: none - Pan: none - edit_rate: 30/1 (30.00) - "Audio 1" - Clip:0 Channel: 1 Gain: none GainAuto: none Start: 158804100 Len: 44100 End: 158848200 SrcOffset: 44100 - SourceFile: [ch 1] PT_MXF_ExtepwwsVYMTxgrsYBFR-01 (PT_MXF_ExtepwwsVYMTxgrsYBFR-01) - - + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO Name: "Audio 1" + └── Clip (1): Start: 158804100 Len: 44100 End: 158848200 SourceOffset: 44100 Channels: 1 + └── SourceFile [ch 1]: "PT_MXF_ExtepwwsVYMTxgrsYBFR-01" + diff --git a/test/expected/PT_Multichannel_5.1_multi_source.aaf.expected b/test/expected/PT_Multichannel_5.1_multi_source.aaf.expected index 0071ba9..f6f905c 100644 --- a/test/expected/PT_Multichannel_5.1_multi_source.aaf.expected +++ b/test/expected/PT_Multichannel_5.1_multi_source.aaf.expected @@ -35,39 +35,61 @@ Dominant Sample Rate : 32000 Dominant Sample Size : 16 bits - UserComments : - [0] Name: "Comment" Text: "" + Metadata: + - Name: "Comment" Text: "" Media Essences : ================ - 0: Type: WAVE Length: 1067 01 Ch - 32000 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichapxmrVWSQqrssFPBB.wav file_name: Sample accurate edit (Sample accurate edit_5) - 1: Type: WAVE Length: 1067 01 Ch - 32000 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichaxrqhVWSQqzrsFPBB.wav file_name: Sample accurate edit (Sample accurate edit_4) - 2: Type: WAVE Length: 1067 01 Ch - 32000 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichargmdVWSQqprsFPBB.wav file_name: Sample accurate edit (Sample accurate edit_3) - 3: Type: WAVE Length: 1067 01 Ch - 32000 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichasrsyTWSQzxqsFPBB.wav file_name: Sample accurate edit (Sample accurate edit_2) - 4: Type: WAVE Length: 1067 01 Ch - 32000 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichaycrvTWSQbmqsFPBB.wav file_name: Sample accurate edit (Sample accurate edit_1) - 5: Type: WAVE Length: 1067 01 Ch - 32000 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichavvmqTWSQzxpsFPBB.wav file_name: Sample accurate edit - 6: Type: WAVE Length: 227201 01 Ch - 32000 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichadhmpVWSQhgssFPBB.wav file_name: 5.1-SMPTE-channel-identif-02.LFE - 7: Type: WAVE Length: 227201 01 Ch - 32000 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichazrrfVWSQrsrsFPBB.wav file_name: 5.1-SMPTE-channel-identif-02.Rs - 8: Type: WAVE Length: 227201 01 Ch - 32000 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichayhhbVWSQfdrsFPBB.wav file_name: 5.1-SMPTE-channel-identif-02.Ls - 9: Type: WAVE Length: 227201 01 Ch - 32000 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichahxvwTWSQbrqsFPBB.wav file_name: 5.1-SMPTE-channel-identif-02.R - 10: Type: WAVE Length: 227201 01 Ch - 32000 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichahzrrTWSQbcqsFPBB.wav file_name: 5.1-SMPTE-channel-identif-02.C - 11: Type: WAVE Length: 227201 01 Ch - 32000 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichaqmfmTWSQhqpsFPBB.wav file_name: 5.1-SMPTE-channel-identif-02.L + Audio[1] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 1067 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_5" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichapxmrVWSQqrssFPBB.wav" + Audio[2] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 1067 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_4" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichaxrqhVWSQqzrsFPBB.wav" -Tracks & Clips : -================ + Audio[3] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 1067 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_3" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichargmdVWSQqprsFPBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 1067 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_2" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichasrsyTWSQzxqsFPBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 1067 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichaycrvTWSQbmqsFPBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 1067 Name: "Sample accurate edit" UniqueName: "Sample accurate edit" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichavvmqTWSQzxpsFPBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 227201 Name: "5.1-SMPTE-channel-identif-02.LFE" UniqueName: "5.1-SMPTE-channel-identif-02.LFE" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichadhmpVWSQhgssFPBB.wav" + + Audio[8] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 227201 Name: "5.1-SMPTE-channel-identif-02.Rs" UniqueName: "5.1-SMPTE-channel-identif-02.Rs" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichazrrfVWSQrsrsFPBB.wav" -Track (1) - 5.1 - Gain: none - Pan: none - edit_rate: 30/1 (30.00) - "Audio 1" - Clip:0 Channel: 6 Gain: none GainAuto: none Start: 9600000 Len: 222933 End: 9822933 SrcOffset: 2133 - SourceFile: [ch 1] 5.1-SMPTE-channel-identif-02.L (5.1-SMPTE-channel-identif-02.L) - SourceFile: [ch 1] 5.1-SMPTE-channel-identif-02.C (5.1-SMPTE-channel-identif-02.C) - SourceFile: [ch 1] 5.1-SMPTE-channel-identif-02.R (5.1-SMPTE-channel-identif-02.R) - SourceFile: [ch 1] 5.1-SMPTE-channel-identif-02.Ls (5.1-SMPTE-channel-identif-02.Ls) - SourceFile: [ch 1] 5.1-SMPTE-channel-identif-02.Rs (5.1-SMPTE-channel-identif-02.Rs) - SourceFile: [ch 1] 5.1-SMPTE-channel-identif-02.LFE (5.1-SMPTE-channel-identif-02.LFE) + Audio[9] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 227201 Name: "5.1-SMPTE-channel-identif-02.Ls" UniqueName: "5.1-SMPTE-channel-identif-02.Ls" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichayhhbVWSQfdrsFPBB.wav" + Audio[10] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 227201 Name: "5.1-SMPTE-channel-identif-02.R" UniqueName: "5.1-SMPTE-channel-identif-02.R" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichahxvwTWSQbrqsFPBB.wav" + + Audio[11] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 227201 Name: "5.1-SMPTE-channel-identif-02.C" UniqueName: "5.1-SMPTE-channel-identif-02.C" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichahzrrTWSQbcqsFPBB.wav" + + Audio[12] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 227201 Name: "5.1-SMPTE-channel-identif-02.L" UniqueName: "5.1-SMPTE-channel-identif-02.L" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_5.1_multi_source/PT_MultichaqmfmTWSQhqpsFPBB.wav" + + +Tracks & Clips : +================ + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: 5.1 Name: "Audio 1" + └── Clip (1): Start: 9600000 Len: 224000 End: 9824000 SourceOffset: 2133 Channels: 6 + ├── SourceFile [ch 1]: "5.1-SMPTE-channel-identif-02.L" + ├── SourceFile [ch 1]: "5.1-SMPTE-channel-identif-02.C" + ├── SourceFile [ch 1]: "5.1-SMPTE-channel-identif-02.R" + ├── SourceFile [ch 1]: "5.1-SMPTE-channel-identif-02.Ls" + ├── SourceFile [ch 1]: "5.1-SMPTE-channel-identif-02.Rs" + └── SourceFile [ch 1]: "5.1-SMPTE-channel-identif-02.LFE" + diff --git a/test/expected/PT_Multichannel_7.1_multi_source.aaf.expected b/test/expected/PT_Multichannel_7.1_multi_source.aaf.expected index 39cc099..0b5adc8 100644 --- a/test/expected/PT_Multichannel_7.1_multi_source.aaf.expected +++ b/test/expected/PT_Multichannel_7.1_multi_source.aaf.expected @@ -35,45 +35,75 @@ Dominant Sample Rate : 44100 Dominant Sample Size : 16 bits - UserComments : - [0] Name: "Comment" Text: "" + Metadata: + - Name: "Comment" Text: "" Media Essences : ================ - 0: Type: WAVE Length: 1471 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichabbdvJMHRfxfcVQBB.wav file_name: Sample accurate edit (Sample accurate edit_7) - 1: Type: WAVE Length: 1471 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichahdwqJMHRdpfcVQBB.wav file_name: Sample accurate edit (Sample accurate edit_6) - 2: Type: WAVE Length: 1471 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichaqppmJMHRgcfcVQBB.wav file_name: Sample accurate edit (Sample accurate edit_5) - 3: Type: WAVE Length: 1471 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichacmfgJMHRqvdcVQBB.wav file_name: Sample accurate edit (Sample accurate edit_4) - 4: Type: WAVE Length: 1471 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichamsycJMHRshdcVQBB.wav file_name: Sample accurate edit (Sample accurate edit_3) - 5: Type: WAVE Length: 1471 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichabzrzHMHRwzccVQBB.wav file_name: Sample accurate edit (Sample accurate edit_2) - 6: Type: WAVE Length: 1471 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichawggxHMHRwrccVQBB.wav file_name: Sample accurate edit (Sample accurate edit_1) - 7: Type: WAVE Length: 1471 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichabhzsHMHRxfccVQBB.wav file_name: Sample accurate edit - 8: Type: WAVE Length: 482161 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichaxrzrJMHRgsfcVQBB.wav file_name: 7.1-SMPTE-channel-identif.1-01.LFE - 9: Type: WAVE Length: 482161 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichaqprpJMHRdgfcVQBB.wav file_name: 7.1-SMPTE-channel-identif.1-01.Rs - 10: Type: WAVE Length: 482161 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichaychhJMHRhydcVQBB.wav file_name: 7.1-SMPTE-channel-identif.1-01.Ls - 11: Type: WAVE Length: 482161 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichafwbfJMHRqqdcVQBB.wav file_name: 7.1-SMPTE-channel-identif.1-01.R - 12: Type: WAVE Length: 482161 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichawzvbJMHRsddcVQBB.wav file_name: 7.1-SMPTE-channel-identif.1-01.Rc - 13: Type: WAVE Length: 482161 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichawrmyHMHRswccVQBB.wav file_name: 7.1-SMPTE-channel-identif.1-01.C - 14: Type: WAVE Length: 482161 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichabxcwHMHRwmccVQBB.wav file_name: 7.1-SMPTE-channel-identif.1-01.Lc - 15: Type: WAVE Length: 482161 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichaypsrHMHRqbccVQBB.wav file_name: 7.1-SMPTE-channel-identif.1-01.L + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_7" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichabbdvJMHRfxfcVQBB.wav" + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_6" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichahdwqJMHRdpfcVQBB.wav" -Tracks & Clips : -================ + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_5" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichaqppmJMHRgcfcVQBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_4" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichacmfgJMHRqvdcVQBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_3" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichamsycJMHRshdcVQBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_2" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichabzrzHMHRwzccVQBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichawggxHMHRwrccVQBB.wav" + + Audio[8] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichabhzsHMHRxfccVQBB.wav" + + Audio[9] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 482161 Name: "7.1-SMPTE-channel-identif.1-01.LFE" UniqueName: "7.1-SMPTE-channel-identif.1-01.LFE" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichaxrzrJMHRgsfcVQBB.wav" + + Audio[10] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 482161 Name: "7.1-SMPTE-channel-identif.1-01.Rs" UniqueName: "7.1-SMPTE-channel-identif.1-01.Rs" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichaqprpJMHRdgfcVQBB.wav" -Track (1) - 7.1 - Gain: none - Pan: none - edit_rate: 30/1 (30.00) - "Audio 1" - Clip:0 Channel: 8 Gain: none GainAuto: none Start: 13230000 Len: 473340 End: 13703340 SrcOffset: 4410 - SourceFile: [ch 1] 7.1-SMPTE-channel-identif.1-01.L (7.1-SMPTE-channel-identif.1-01.L) - SourceFile: [ch 1] 7.1-SMPTE-channel-identif.1-01.Lc (7.1-SMPTE-channel-identif.1-01.Lc) - SourceFile: [ch 1] 7.1-SMPTE-channel-identif.1-01.C (7.1-SMPTE-channel-identif.1-01.C) - SourceFile: [ch 1] 7.1-SMPTE-channel-identif.1-01.Rc (7.1-SMPTE-channel-identif.1-01.Rc) - SourceFile: [ch 1] 7.1-SMPTE-channel-identif.1-01.R (7.1-SMPTE-channel-identif.1-01.R) - SourceFile: [ch 1] 7.1-SMPTE-channel-identif.1-01.Ls (7.1-SMPTE-channel-identif.1-01.Ls) - SourceFile: [ch 1] 7.1-SMPTE-channel-identif.1-01.Rs (7.1-SMPTE-channel-identif.1-01.Rs) - SourceFile: [ch 1] 7.1-SMPTE-channel-identif.1-01.LFE (7.1-SMPTE-channel-identif.1-01.LFE) + Audio[11] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 482161 Name: "7.1-SMPTE-channel-identif.1-01.Ls" UniqueName: "7.1-SMPTE-channel-identif.1-01.Ls" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichaychhJMHRhydcVQBB.wav" + Audio[12] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 482161 Name: "7.1-SMPTE-channel-identif.1-01.R" UniqueName: "7.1-SMPTE-channel-identif.1-01.R" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichafwbfJMHRqqdcVQBB.wav" + + Audio[13] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 482161 Name: "7.1-SMPTE-channel-identif.1-01.Rc" UniqueName: "7.1-SMPTE-channel-identif.1-01.Rc" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichawzvbJMHRsddcVQBB.wav" + + Audio[14] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 482161 Name: "7.1-SMPTE-channel-identif.1-01.C" UniqueName: "7.1-SMPTE-channel-identif.1-01.C" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichawrmyHMHRswccVQBB.wav" + + Audio[15] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 482161 Name: "7.1-SMPTE-channel-identif.1-01.Lc" UniqueName: "7.1-SMPTE-channel-identif.1-01.Lc" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichabxcwHMHRwmccVQBB.wav" + + Audio[16] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 482161 Name: "7.1-SMPTE-channel-identif.1-01.L" UniqueName: "7.1-SMPTE-channel-identif.1-01.L" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_7.1_multi_source/PT_MultichaypsrHMHRqbccVQBB.wav" + + +Tracks & Clips : +================ + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: 7.1 Name: "Audio 1" + └── Clip (1): Start: 13230000 Len: 474810 End: 13704810 SourceOffset: 4410 Channels: 8 + ├── SourceFile [ch 1]: "7.1-SMPTE-channel-identif.1-01.L" + ├── SourceFile [ch 1]: "7.1-SMPTE-channel-identif.1-01.Lc" + ├── SourceFile [ch 1]: "7.1-SMPTE-channel-identif.1-01.C" + ├── SourceFile [ch 1]: "7.1-SMPTE-channel-identif.1-01.Rc" + ├── SourceFile [ch 1]: "7.1-SMPTE-channel-identif.1-01.R" + ├── SourceFile [ch 1]: "7.1-SMPTE-channel-identif.1-01.Ls" + ├── SourceFile [ch 1]: "7.1-SMPTE-channel-identif.1-01.Rs" + └── SourceFile [ch 1]: "7.1-SMPTE-channel-identif.1-01.LFE" + diff --git a/test/expected/PT_Multichannel_stereo_multi_source.aaf.expected b/test/expected/PT_Multichannel_stereo_multi_source.aaf.expected index 2436448..daf6755 100644 --- a/test/expected/PT_Multichannel_stereo_multi_source.aaf.expected +++ b/test/expected/PT_Multichannel_stereo_multi_source.aaf.expected @@ -35,27 +35,33 @@ Dominant Sample Rate : 44100 Dominant Sample Size : 16 bits - UserComments : - [0] Name: "Comment" Text: "" + Metadata: + - Name: "Comment" Text: "" Media Essences : ================ - 0: Type: WAVE Length: 1471 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_stereo_multi_source/PT_MultichacsgdMFRRgymmQRBB.wav file_name: Sample accurate edit (Sample accurate edit_1) - 1: Type: WAVE Length: 1471 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_stereo_multi_source/PT_MultichaydzzJFRRgqmmQRBB.wav file_name: Sample accurate edit - 2: Type: WAVE Length: 88201 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_stereo_multi_source/PT_MultichapyccMFRRgvmmQRBB.wav file_name: stereo-identif-01.R - 3: Type: WAVE Length: 88201 01 Ch - 44100 Hz - 16 bits file: file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_stereo_multi_source/PT_MultichammsyJFRRzgmmQRBB.wav file_name: stereo-identif-01.L + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_stereo_multi_source/PT_MultichacsgdMFRRgymmQRBB.wav" + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_stereo_multi_source/PT_MultichaydzzJFRRgqmmQRBB.wav" -Tracks & Clips : -================ + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 88201 Name: "stereo-identif-01.R" UniqueName: "stereo-identif-01.R" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_stereo_multi_source/PT_MultichapyccMFRRgvmmQRBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 88201 Name: "stereo-identif-01.L" UniqueName: "stereo-identif-01.L" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/PT_Multichannel_stereo_multi_source/PT_MultichammsyJFRRzgmmQRBB.wav" -Track (1) - STEREO - Gain: none - Pan: none - edit_rate: 30/1 (30.00) - "Audio 1" - Clip:0 Channel: 2 Gain: none GainAuto: none Start: 13230000 Len: 77910 End: 13307910 SrcOffset: 2940 - SourceFile: [ch 1] stereo-identif-01.L (stereo-identif-01.L) - SourceFile: [ch 1] stereo-identif-01.R (stereo-identif-01.R) +Tracks & Clips : +================ + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: STEREO Name: "Audio 1" + └── Clip (1): Start: 13230000 Len: 79380 End: 13309380 SourceOffset: 2940 Channels: 2 + ├── SourceFile [ch 1]: "stereo-identif-01.L" + └── SourceFile [ch 1]: "stereo-identif-01.R" + diff --git a/test/expected/PT_PCM_Internal.aaf.expected b/test/expected/PT_PCM_Internal.aaf.expected index 6d614fe..fc0b821 100644 --- a/test/expected/PT_PCM_Internal.aaf.expected +++ b/test/expected/PT_PCM_Internal.aaf.expected @@ -35,23 +35,23 @@ Dominant Sample Rate : 16000 Dominant Sample Size : 16 bits - UserComments : - [0] Name: "Comment" Text: "" + Metadata: + - Name: "Comment" Text: "" Media Essences : ================ - 0: Type: PCM Length: 32000 01 Ch - 16000 Hz - 16 bits file: EMBEDDED file_name: 1000hz-18dbs16b44.1k-01 + Audio[1] :: Format: PCM - 01 ch - 16000 Hz - 16 bits Length: 32000 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "EMBEDDED" Tracks & Clips : ================ -Track (1) - MONO - Gain: none - Pan: none - edit_rate: 16000/1 (16000.00) - "Audio 1" - Clip:0 Channel: 1 Gain: none GainAuto: none Start: 158760000 Len: 88200 End: 158848200 SrcOffset: 0 - SourceFile: [ch 1] 1000hz-18dbs16b44.1k-01 (1000hz-18dbs16b44.1k-01) - - + AudioTrack[1] :: EditRate: 16000/1 (16000.00) Format: MONO Name: "Audio 1" + └── Clip (1): Start: 158760000 Len: 88200 End: 158848200 SourceOffset: 0 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + diff --git a/test/expected/PT_UTF8_EssencePath.aaf.expected b/test/expected/PT_UTF8_EssencePath.aaf.expected new file mode 100644 index 0000000..e616649 --- /dev/null +++ b/test/expected/PT_UTF8_EssencePath.aaf.expected @@ -0,0 +1,57 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-02-11 22:04:52.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-02-11 22:04:47.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x79fa772d 0x0bc7 0x4c82 { 0xb4 0x94 0x10 0x51 0xa5 0x7b 0x57 0x43 } } + + + + Composition Name : PT_UTF8_EssencePath + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 2493952 (EditRate: 44100/1) + Composition End (samples) : 2493952 + Composition End : 00:00:56:16 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 3444 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "./الفوضى/PT_UTF8_EsszxcxBYZCdpbxHBBB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 44100/1 (44100.00) Format: MONO + └── Clip (1): Start: 2490508 Len: 3444 End: 2493952 SourceOffset: 0 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + + diff --git a/test/expected/PT_WAV_External.aaf.expected b/test/expected/PT_WAV_External.aaf.expected index d09f03d..fc12e7d 100644 --- a/test/expected/PT_WAV_External.aaf.expected +++ b/test/expected/PT_WAV_External.aaf.expected @@ -35,23 +35,23 @@ Dominant Sample Rate : 44100 Dominant Sample Size : 16 bits - UserComments : - [0] Name: "Comment" Text: "" + Metadata: + - Name: "Comment" Text: "" Media Essences : ================ - 0: Type: WAVE Length: 132300 01 Ch - 44100 Hz - 16 bits file: /home/agfline/Programming/libaaf/LibAAF/test/res/1000hz-18dbs16b44.1k.wav file_name: 1000hz-18dbs16b44.1k-01 + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 132300 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "../res/1000hz-18dbs16b44.1k.wav" Tracks & Clips : ================ -Track (1) - MONO - Gain: none - Pan: none - edit_rate: 44100/1 (44100.00) - "Audio 1" - Clip:0 Channel: 1 Gain: none GainAuto: none Start: 158804100 Len: 44100 End: 158848200 SrcOffset: 44100 - SourceFile: [ch 1] 1000hz-18dbs16b44.1k-01 (1000hz-18dbs16b44.1k-01) - - + AudioTrack[1] :: EditRate: 44100/1 (44100.00) Format: MONO Name: "Audio 1" + └── Clip (1): Start: 158804100 Len: 44100 End: 158848200 SourceOffset: 44100 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + diff --git a/test/expected/PT_WAV_External_same_directory.aaf.expected b/test/expected/PT_WAV_External_same_directory.aaf.expected index e283945..dc8762a 100644 --- a/test/expected/PT_WAV_External_same_directory.aaf.expected +++ b/test/expected/PT_WAV_External_same_directory.aaf.expected @@ -35,23 +35,23 @@ Dominant Sample Rate : 32000 Dominant Sample Size : 16 bits - UserComments : - [0] Name: "Comment" Text: "" + Metadata: + - Name: "Comment" Text: "" Media Essences : ================ - 0: Type: WAVE Length: 64001 01 Ch - 32000 Hz - 16 bits file: /home/agfline/Programming/libaaf/LibAAF/test/aaf/PT_WAV_ExtehcrfPFTBxvdzJCBB.wav file_name: 1000hz-18dbs16b44.1k-01 + Audio[1] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 64001 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "./PT_WAV_ExtehcrfPFTBxvdzJCBB.wav" Tracks & Clips : ================ -Track (1) - MONO - Gain: none - Pan: none - edit_rate: 30/1 (30.00) - "Audio 1" - Clip:0 Channel: 1 Gain: none GainAuto: none Start: 158760000 Len: 88200 End: 158848200 SrcOffset: 0 - SourceFile: [ch 1] 1000hz-18dbs16b44.1k-01 (1000hz-18dbs16b44.1k-01) - - + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO Name: "Audio 1" + └── Clip (1): Start: 158760000 Len: 88200 End: 158848200 SourceOffset: 0 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + diff --git a/test/expected/PT_WAV_External_sub_directory.aaf.expected b/test/expected/PT_WAV_External_sub_directory.aaf.expected index 3d47b42..11acd72 100644 --- a/test/expected/PT_WAV_External_sub_directory.aaf.expected +++ b/test/expected/PT_WAV_External_sub_directory.aaf.expected @@ -35,23 +35,23 @@ Dominant Sample Rate : 32000 Dominant Sample Size : 16 bits - UserComments : - [0] Name: "Comment" Text: "" + Metadata: + - Name: "Comment" Text: "" Media Essences : ================ - 0: Type: WAVE Length: 64001 01 Ch - 32000 Hz - 16 bits file: /home/agfline/Programming/libaaf/LibAAF/test/aaf/PT_WAV_External_sub_directory/PT_WAV_ExterqqqHXSBxbzcJCBB.wav file_name: 1000hz-18dbs16b44.1k-01 + Audio[1] :: Format: WAVE - 01 ch - 32000 Hz - 16 bits Length: 64001 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "./PT_WAV_External_sub_directory/PT_WAV_ExterqqqHXSBxbzcJCBB.wav" Tracks & Clips : ================ -Track (1) - MONO - Gain: none - Pan: none - edit_rate: 30/1 (30.00) - "Audio 1" - Clip:0 Channel: 1 Gain: none GainAuto: none Start: 158760000 Len: 88200 End: 158848200 SrcOffset: 0 - SourceFile: [ch 1] 1000hz-18dbs16b44.1k-01 (1000hz-18dbs16b44.1k-01) - - + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO Name: "Audio 1" + └── Clip (1): Start: 158760000 Len: 88200 End: 158848200 SourceOffset: 0 Channels: 1 + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + diff --git a/test/expected/PT_lang_de.aaf.expected b/test/expected/PT_lang_de.aaf.expected new file mode 100644 index 0000000..5789499 --- /dev/null +++ b/test/expected/PT_lang_de.aaf.expected @@ -0,0 +1,75 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-09 22:09:00.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-01-09 22:08:57.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xf6bfd145 0xed00 0x4d2d { 0xb9 0xab 0x42 0x5b 0x34 0x8c 0x38 0xe4 } } + + + + Composition Name : PT_lang_de + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 9055 (EditRate: 30/1) + Composition End (samples) : 13310850 + Composition End : 00:05:01:25 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Samplegenaue Bearbeitung" UniqueName: "Samplegenaue Bearbeitung_3" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_dehfdyMMBSqfpqBBBB.wav" + + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 19111 Name: "Fade " UniqueName: "Fade _1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_deddbxMMBSsbpqBBBB.wav" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Samplegenaue Bearbeitung" UniqueName: "Samplegenaue Bearbeitung_2" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_deywxvMMBSvxmqBBBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 130831 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_dewqvsMMBSwsmqBBBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Samplegenaue Bearbeitung" UniqueName: "Samplegenaue Bearbeitung_1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_dedyqrMMBSwpmqBBBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "Fade " UniqueName: "Fade " + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_devyfqMMBSpgmqBBBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Samplegenaue Bearbeitung" UniqueName: "Samplegenaue Bearbeitung" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_dergxmMMBSxbmqBBBB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO + └── Clip (1): Start: 13232940 Len: 77910 End: 13310850 SourceOffset: 29400 Channels: 1 FadeIn: CURV_LIN (16170) FadeOut: CURV_LIN (17640) + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + + diff --git a/test/expected/PT_lang_en.aaf.expected b/test/expected/PT_lang_en.aaf.expected new file mode 100644 index 0000000..82bc39a --- /dev/null +++ b/test/expected/PT_lang_en.aaf.expected @@ -0,0 +1,75 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-09 21:57:04.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-01-09 21:56:47.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xa5f7eadb 0x4217 0x4c1f { 0x99 0xc2 0xb2 0x85 0x23 0xa5 0x54 0x3a } } + + + + Composition Name : PT_lang_en + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 9055 (EditRate: 30/1) + Composition End (samples) : 13310850 + Composition End : 00:05:01:25 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_3" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_endgqhBCWRmczmCSBB.wav" + + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 19111 Name: "Fade " UniqueName: "Fade _1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_enbscgBCWRwxymCSBB.wav" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_2" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_enwczdBCWRxsymCSBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 133771 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_enwvwcBCWRypymCSBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit_1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_ensrrbBCWRxgymCSBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "Fade " UniqueName: "Fade " + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_enxcpzZBWRycymCSBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Sample accurate edit" UniqueName: "Sample accurate edit" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_endhdyZBWRqyxmCSBB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO + └── Clip (1): Start: 13232940 Len: 77910 End: 13310850 SourceOffset: 32340 Channels: 1 FadeIn: CURV_LIN (16170) FadeOut: CURV_LIN (17640) + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + + diff --git a/test/expected/PT_lang_es.aaf.expected b/test/expected/PT_lang_es.aaf.expected new file mode 100644 index 0000000..9430bbb --- /dev/null +++ b/test/expected/PT_lang_es.aaf.expected @@ -0,0 +1,75 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-09 22:10:15.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-01-09 22:10:11.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x67f71f04 0x2033 0x42ae { 0x95 0x79 0x1a 0x93 0x32 0x7f 0xf8 0xd0 } } + + + + Composition Name : PT_lang_es + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 9055 (EditRate: 30/1) + Composition End (samples) : 13310850 + Composition End : 00:05:01:25 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Edición con precisión de muestra" UniqueName: "Edición con precisión de muestra_3" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_esbrhmRWBSmdfrBBBB.wav" + + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 19111 Name: "Fundido " UniqueName: "Fundido _1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_esxrygRWBSvydrBBBB.wav" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Edición con precisión de muestra" UniqueName: "Edición con precisión de muestra_2" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_esshrfRWBShvdrBBBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 130831 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_eshwmdRWBShqdrBBBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Edición con precisión de muestra" UniqueName: "Edición con precisión de muestra_1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_esffgcRWBSmhdrBBBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "Fundido " UniqueName: "Fundido " + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_esvcdbRWBSpddrBBBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Edición con precisión de muestra" UniqueName: "Edición con precisión de muestra" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_esgfxyQWBSdzcrBBBB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO + └── Clip (1): Start: 13232940 Len: 77910 End: 13310850 SourceOffset: 29400 Channels: 1 FadeIn: CURV_LIN (16170) FadeOut: CURV_LIN (17640) + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + + diff --git a/test/expected/PT_lang_fr.aaf.expected b/test/expected/PT_lang_fr.aaf.expected new file mode 100644 index 0000000..c2f5123 --- /dev/null +++ b/test/expected/PT_lang_fr.aaf.expected @@ -0,0 +1,75 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-09 22:07:50.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-01-09 22:07:46.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xadf3200b 0x3149 0x48c7 { 0x98 0xee 0x23 0xc0 0xf2 0x78 0x0a 0xb3 } } + + + + Composition Name : PT_lang_fr + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 9055 (EditRate: 30/1) + Composition End (samples) : 13310850 + Composition End : 00:05:01:25 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Modification à l'échantillon près" UniqueName: "Modification à l'échantillon près_3" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_frspvmTYZRcpgxBBBB.wav" + + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 19111 Name: "Fondu " UniqueName: "Fondu _1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_frdvqhTYZRcggxBBBB.wav" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Modification à l'échantillon près" UniqueName: "Modification à l'échantillon près_2" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_frfrhgTYZRbcgxBBBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 130831 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_frvbffTYZRbyfxBBBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Modification à l'échantillon près" UniqueName: "Modification à l'échantillon près_1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_frpyzcTYZRzsfxBBBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "Fondu " UniqueName: "Fondu " + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_frzwxbTYZRcqfxBBBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "Modification à l'échantillon près" UniqueName: "Modification à l'échantillon près" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_frgyqzSYZRvgfxBBBB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO + └── Clip (1): Start: 13232940 Len: 77910 End: 13310850 SourceOffset: 29400 Channels: 1 FadeIn: CURV_LIN (16170) FadeOut: CURV_LIN (17640) + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + + diff --git a/test/expected/PT_lang_ja.aaf.expected b/test/expected/PT_lang_ja.aaf.expected new file mode 100644 index 0000000..3ca45ad --- /dev/null +++ b/test/expected/PT_lang_ja.aaf.expected @@ -0,0 +1,75 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-09 21:58:36.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-01-09 21:58:31.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0xe852c987 0x8dcd 0x45ce { 0xad 0x2f 0xf8 0xe5 0x23 0x14 0x29 0x67 } } + + + + Composition Name : PT_lang_ja + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 9055 (EditRate: 30/1) + Composition End (samples) : 13310850 + Composition End : 00:05:01:25 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "サンプル精度編集" UniqueName: "サンプル精度編集_3" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_jawmpmXSWRfmyvBBBB.wav" + + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 19111 Name: "Fade " UniqueName: "Fade _1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_jafhxgXSWRbdyvBBBB.wav" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "サンプル精度編集" UniqueName: "サンプル精度編集_2" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_jaqmcfXSWRqxxvBBBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 130831 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_jawfzcXSWRssxvBBBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "サンプル精度編集" UniqueName: "サンプル精度編集_1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_japrwbXSWRspxvBBBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "Fade " UniqueName: "Fade " + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_javdgzWSWRwfxvBBBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "サンプル精度編集" UniqueName: "サンプル精度編集" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_jawsgxWSWRvywvBBBB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO + └── Clip (1): Start: 13232940 Len: 77910 End: 13310850 SourceOffset: 29400 Channels: 1 FadeIn: CURV_LIN (16170) FadeOut: CURV_LIN (17640) + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + + diff --git a/test/expected/PT_lang_ko.aaf.expected b/test/expected/PT_lang_ko.aaf.expected new file mode 100644 index 0000000..88b4fc0 --- /dev/null +++ b/test/expected/PT_lang_ko.aaf.expected @@ -0,0 +1,75 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-09 22:06:39.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-01-09 22:06:36.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x3e79665b 0x9628 0x42fd { 0x96 0x44 0xdc 0xdc 0xbe 0x59 0xc3 0xdf } } + + + + Composition Name : PT_lang_ko + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 9055 (EditRate: 30/1) + Composition End (samples) : 13310850 + Composition End : 00:05:01:25 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "샘플 단위 정밀 편집" UniqueName: "샘플 단위 정밀 편집_3" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_kosphrYQZRqxxsBBBB.wav" + + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 19111 Name: "페이드" UniqueName: "페이드_1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_koczrpYQZRcrxsBBBB.wav" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "샘플 단위 정밀 편집" UniqueName: "샘플 단위 정밀 편집_2" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_kobmpmYQZRdmxsBBBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 130831 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_kocdhhYQZRffxsBBBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "샘플 단위 정밀 편집" UniqueName: "샘플 단위 정밀 편집_1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_kofsdgYQZRgbxsBBBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "페이드" UniqueName: "페이드" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_kowgbfYQZRhxwsBBBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "샘플 단위 정밀 편집" UniqueName: "샘플 단위 정밀 편집" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_korsrcYQZRvrwsBBBB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO + └── Clip (1): Start: 13232940 Len: 77910 End: 13310850 SourceOffset: 29400 Channels: 1 FadeIn: CURV_LIN (16170) FadeOut: CURV_LIN (17640) + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + + diff --git a/test/expected/PT_lang_zh_CN.aaf.expected b/test/expected/PT_lang_zh_CN.aaf.expected new file mode 100644 index 0000000..f9d3e63 --- /dev/null +++ b/test/expected/PT_lang_zh_CN.aaf.expected @@ -0,0 +1,75 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-09 22:03:23.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-01-09 22:03:20.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x48624b4b 0x2ab4 0x411f { 0xbe 0x13 0x3a 0xac 0xf1 0x65 0x84 0xd9 } } + + + + Composition Name : PT_lang_zh_CN + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 9055 (EditRate: 30/1) + Composition End (samples) : 13310850 + Composition End : 00:05:01:25 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "精确采样编辑" UniqueName: "精确采样编辑_3" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_rmpzHMYRvphwBBBB.wav" + + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 19111 Name: "淡变 " UniqueName: "淡变 _1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_ppgyHMYRvghwBBBB.wav" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "精确采样编辑" UniqueName: "精确采样编辑_2" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_wpqwHMYRfbhwBBBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 130831 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_hmmvHMYRhxgwBBBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "精确采样编辑" UniqueName: "精确采样编辑_1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_syfsHMYRhsgwBBBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "淡变 " UniqueName: "淡变 " + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_cvcrHMYRppgwBBBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "精确采样编辑" UniqueName: "精确采样编辑" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_svvpHMYRyfgwBBBB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO + └── Clip (1): Start: 13232940 Len: 77910 End: 13310850 SourceOffset: 29400 Channels: 1 FadeIn: CURV_LIN (16170) FadeOut: CURV_LIN (17640) + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + + diff --git a/test/expected/PT_lang_zh_TW.aaf.expected b/test/expected/PT_lang_zh_TW.aaf.expected new file mode 100644 index 0000000..338ab6b --- /dev/null +++ b/test/expected/PT_lang_zh_TW.aaf.expected @@ -0,0 +1,75 @@ + + ByteOrder : Little-Endian (0x4949) + LastModified : 2024-01-09 22:05:29.00 + AAF ObjSpec Version : 1.1 + ObjectModel Version : 1 + Operational Pattern : AAFUID_NULL + + + + CompanyName : Digidesign, Inc. + ProductName : ProTools + ProductVersion : 23.12.0.136 AAFVersionReleased (1) + ProductVersionString : 23.12.0.136 + ProductID : { 0x319414f6 0x5852 0x4050 { 0xa4 0xeb 0x98 0x1e 0x64 0x3f 0x33 0xa2 } } + Date : 2024-01-09 22:05:25.00 + ToolkitVersion : 1.1.6.0 AAFVersionBeta (4) + Platform : AAFSDK (Win64) + GenerationAUID : { 0x33ae7f64 0x0a42 0x46c5 { 0xb7 0x9f 0xb0 0x19 0xa1 0xe6 0x1c 0x1d } } + + + + Composition Name : PT_lang_zh_TW + + TC EditRrate : 30/1 + TC FPS : 30 NDF + + Composition Start (EU) : 0 + Composition Start (samples) : 0 + Composition Start : 00:00:00:00 + + Composition End (EU) : 9055 (EditRate: 30/1) + Composition End (samples) : 13310850 + Composition End : 00:05:01:25 + + Dominant Sample Rate : 44100 + Dominant Sample Size : 16 bits + + Metadata: + - Name: "Comment" Text: "" + + +Media Essences : +================ + + Audio[1] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "精確取樣編輯" UniqueName: "精確取樣編輯_3" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_pqszFCZRghypCBBB.wav" + + Audio[2] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 19111 Name: "淡變 " UniqueName: "淡變 _1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_swpyFCZRgdypCBBB.wav" + + Audio[3] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "精確取樣編輯" UniqueName: "精確取樣編輯_2" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_dwswFCZRsxxpCBBB.wav" + + Audio[4] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 130831 Name: "1000hz-18dbs16b44.1k-01" UniqueName: "1000hz-18dbs16b44.1k-01" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_pmqvFCZRvsxpCBBB.wav" + + Audio[5] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "精確取樣編輯" UniqueName: "精確取樣編輯_1" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_xwhsFCZRvpxpCBBB.wav" + + Audio[6] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 16171 Name: "淡變 " UniqueName: "淡變 " + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_vrfrFCZRwgxpCBBB.wav" + + Audio[7] :: Format: WAVE - 01 ch - 44100 Hz - 16 bits Length: 1471 Name: "精確取樣編輯" UniqueName: "精確取樣編輯" + └── File: "file:///c%3a/Users/user/Desktop/LibAAFTestFiles/tmp/dumb/PT_lang_zh_gzxpFCZRhcxpCBBB.wav" + + +Tracks & Clips : +================ + + + AudioTrack[1] :: EditRate: 30/1 (30.00) Format: MONO + └── Clip (1): Start: 13232940 Len: 77910 End: 13310850 SourceOffset: 29400 Channels: 1 FadeIn: CURV_LIN (16170) FadeOut: CURV_LIN (17640) + └── SourceFile [ch 1]: "1000hz-18dbs16b44.1k-01" + + diff --git a/test/test.py b/test/test.py new file mode 100755 index 0000000..6aac547 --- /dev/null +++ b/test/test.py @@ -0,0 +1,456 @@ +#!/bin/python3 + +import io +import os +import sys +import subprocess +import difflib +import argparse +import hashlib + +errorCounts = 0 + +parser = argparse.ArgumentParser() +parser.add_argument('--aaftool') +parser.add_argument('--update', action='store_true') +parser.add_argument('--wine', action='store_true') +parser.add_argument('--run-from-cmake', action='store_true') +args = parser.parse_args() + +if sys.platform.startswith('win32'): + DIR_SEP = "\\" + BIN_AAFTOOL = "aaftool.exe" +else: + DIR_SEP = "/" + BIN_AAFTOOL = "aaftool" + + +TEST_DIR = os.path.dirname(os.path.abspath(__file__)) +TEST_AAF_DIR = TEST_DIR + DIR_SEP + "aaf" +TEST_EXPECTED_DIR = TEST_DIR + DIR_SEP + "expected" +TEST_MEDIA_DIR = TEST_DIR + DIR_SEP + "res" +TEST_OUTPUT_PATH = TEST_DIR + DIR_SEP + "output" + +PROJ_DIR = os.path.dirname(TEST_DIR) +BIN_DIR = PROJ_DIR + DIR_SEP + "build" + DIR_SEP + "bin" + +BIN_GREP = "" +BIN_DIFF = "" +BIN_VALGRIND = "" + +if args.aaftool != None: + AAFTOOL_CMD = "\"" + args.aaftool + "\" --aaf-summary --aaf-essences --aaf-clips --pos-format samples --show-automation --show-metadata" +else: + if args.wine: + AAFTOOL_CMD = "wine " + BIN_DIR + DIR_SEP + BIN_AAFTOOL + ".exe --aaf-summary --aaf-essences --aaf-clips --pos-format samples --show-automation --show-metadata" + else: + AAFTOOL_CMD = BIN_DIR + DIR_SEP + BIN_AAFTOOL + " --aaf-summary --aaf-essences --aaf-clips --pos-format samples --show-automation --show-metadata" + + +GREP_CMD = "" +DIFF_CMD = "" +VALGRIND_CMD = "" + + +# prepare ANSI colors for windows + +if not __import__("sys").stdout.isatty(): + ANSI_COLOR_RED = "" + ANSI_COLOR_CYAN = "" + ANSI_COLOR_GREEN = "" + ANSI_COLOR_ORANGE = "" + ANSI_COLOR_END = "" + +else: + ANSI_COLOR_RED = "\x1b[38;5;124m" + ANSI_COLOR_CYAN = "\x1b[38;5;81m" + ANSI_COLOR_GREEN = "\x1b[92m" + ANSI_COLOR_ORANGE = "\x1b[38;5;130m" + ANSI_COLOR_END = "\x1b[0m" + + # set Windows console in VT mode + if __import__("platform").system() == "Windows": + kernel32 = __import__("ctypes").windll.kernel32 + kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7) + del kernel32 + + +if sys.platform.startswith('linux'): + data = subprocess.run( "which grep", capture_output=True, shell=True, text=True ) + BIN_GREP = data.stdout.rstrip('\n') + + if BIN_GREP == "": + print("Error: can't locate grep") + exit(1) + + data = subprocess.run( "which diff", capture_output=True, shell=True, text=True ) + BIN_DIFF = data.stdout.rstrip('\n') + + if BIN_DIFF == "": + print("Error: can't locate grep") + exit(1) + + DIFF_CMD = BIN_DIFF + + if not args.wine: + data = subprocess.run( "which valgrind", capture_output=True, shell=True, text=True ) + BIN_VALGRIND = data.stdout.rstrip('\n') + + if BIN_VALGRIND == "": + print( "Error: can't locate valgrind" ) + exit(1) + + VALGRIND_CMD = BIN_VALGRIND + " --error-exitcode=1 --track-origins=yes --leak-check=full --show-leak-kinds=all" + +elif sys.platform.startswith('win32'): + BIN_DIFF = 'fc.exe ' + DIFF_CMD = BIN_DIFF + ' /U' + + + + +def test( aafFileName, aaftoolAddCmd ): + + if args.run_from_cmake and args.update: + return + + if args.update: + return update( aafFileName, aaftoolAddCmd ) + + global errorCounts + global VALGRIND_CMD + + if BIN_VALGRIND != "": + print( " [....] [....] ", end="" ) + else: + print( " [....] ", end="" ) + + print(ANSI_COLOR_CYAN + aafFileName + ANSI_COLOR_END, end="") + sys.stdout.flush() + + aafFile = TEST_AAF_DIR + DIR_SEP + aafFileName; + expectedAaftoolOutputFile = TEST_EXPECTED_DIR + DIR_SEP + aafFileName + ".expected" + + valgrindOutputFile = TEST_OUTPUT_PATH + DIR_SEP + aafFileName + ".valgrind" + aaftoolOutputFile = TEST_OUTPUT_PATH + DIR_SEP + aafFileName + ".aaftool" + aaftoolDiffFile = TEST_OUTPUT_PATH + DIR_SEP + aafFileName + ".aaftooldiff" + + if os.path.exists(valgrindOutputFile): + os.remove(valgrindOutputFile) + if os.path.exists(aaftoolOutputFile): + os.remove(aaftoolOutputFile) + if os.path.exists(aaftoolDiffFile): + os.remove(aaftoolDiffFile) + + if not os.path.isfile(aafFile): + print( " : " + ANSI_COLOR_RED + "Missing AAF file \""+aafFile+"\"" + ANSI_COLOR_END ) + errorCounts+=1 + return + + if not os.path.isfile(expectedAaftoolOutputFile): + print( " : " + ANSI_COLOR_RED + "Missing expected-output file \"" + expectedAaftoolOutputFile + "\"" + ANSI_COLOR_END ) + errorCounts+=1 + return + + + valgrindError = False + aaftoolError = False + + valgrindCmd = VALGRIND_CMD + + if valgrindCmd != "": + valgrindCmd += " --quiet --log-file=\"" + valgrindOutputFile + "\" " + + testCmd = valgrindCmd + AAFTOOL_CMD + " " + aaftoolAddCmd + " \"" + aafFile + "\" --verb 0 --no-color --relative-path --log-file \"" + aaftoolOutputFile + "\"" + + proc = subprocess.run(testCmd, capture_output=True, shell=True, text=True, encoding="utf-8") + + if proc.returncode != 0: + if valgrindCmd != "": + valgrindError = True + + if not os.path.isfile(aaftoolOutputFile): + aaftoolError = True; + + + if not aaftoolError: + f1 = open( expectedAaftoolOutputFile, 'r', encoding="utf-8", errors='ignore' ).readlines() + f2 = open( aaftoolOutputFile, 'r', encoding="utf-8", errors='ignore' ).readlines() + + diff = difflib.unified_diff( f1, f2, "expected", "test-output" ) + + fp = open( aaftoolDiffFile, "w", encoding="utf-8" ) + fp.writelines(diff) + fp.close() + + diff = difflib.unified_diff( f1, f2, "expected", "test-output" ) + + if len(list(diff)): + aaftoolError = True; + + + print( "\r ", end="" ) + + if aaftoolError: + print( "[" + ANSI_COLOR_RED + "diff" + ANSI_COLOR_END + "] ", end="" ) + else: + print( "[" + ANSI_COLOR_GREEN + "diff" + ANSI_COLOR_END + "] ", end="" ) + + + if BIN_VALGRIND != "": + if valgrindError: + print( "[" + ANSI_COLOR_RED + "leak" + ANSI_COLOR_END + "] ", end="" ) + else: + print( "[" + ANSI_COLOR_GREEN + "leak" + ANSI_COLOR_END + "] ", end="" ) + + + print( ANSI_COLOR_CYAN + aafFileName + "" + ANSI_COLOR_END ) + + + if valgrindError or aaftoolError: + print( " :: Test command : " + testCmd ) + errorCounts+=1 + + if aaftoolError: + print( " :: expected log : " + expectedAaftoolOutputFile ) + print( " :: test log : " + aaftoolOutputFile ) + print( " :: log diff : " + aaftoolDiffFile ) + + if valgrindError: + print( " :: valgrind log : " + valgrindOutputFile ) + + # if errorCounts and args.run_from_cmake: + # sys.exit(errorCounts); + + + +def extract( aafFileName, aaftoolAddCmd, fileArray ): + + if args.update: + return + + global errorCounts + global VALGRIND_CMD + + if BIN_VALGRIND != "": + print( " [....] [....] ", end="" ) + else: + print( " [....] ", end="" ) + + print( ANSI_COLOR_CYAN + aafFileName + ANSI_COLOR_END, end="" ) + sys.stdout.flush() + + aafFile = TEST_AAF_DIR + DIR_SEP + aafFileName; + expectedAaftoolOutputFile = TEST_EXPECTED_DIR + DIR_SEP + aafFileName + ".expected" + + valgrindOutputFile = TEST_OUTPUT_PATH + DIR_SEP + aafFileName + ".valgrind" + + if os.path.exists(valgrindOutputFile): + os.remove(valgrindOutputFile) + + for file in fileArray: + filepath = TEST_OUTPUT_PATH + DIR_SEP + file[1] + if os.path.exists(filepath): + os.remove(filepath) + + if not os.path.isfile(aafFile): + print( " : " + ANSI_COLOR_RED + "Missing AAF file \""+aafFile+"\"" + ANSI_COLOR_END ) + errorCounts+=1 + return + + + valgrindError = False + hashMismatch = False + + valgrindCmd = VALGRIND_CMD + + if valgrindCmd != "": + valgrindCmd += " --quiet --log-file=\""+valgrindOutputFile+"\" " + + testCmd = valgrindCmd + AAFTOOL_CMD + " " + aaftoolAddCmd + " --extract-path " + TEST_OUTPUT_PATH + " \"" + aafFile + "\"" + + proc = subprocess.run( testCmd, capture_output=True, shell=True, text=True ) + + if proc.returncode != 0: + if valgrindCmd != "": + valgrindError = True + + + for file in fileArray: + validhash = file[0] + filepath = TEST_OUTPUT_PATH + DIR_SEP + file[1] + + if not os.path.isfile(filepath): + print( " : " + ANSI_COLOR_RED + "Missing extracted file \"" + aafFile + "\"" + ANSI_COLOR_END ) + hashMismatch = True + continue + + hash_md5 = hashlib.md5() + + with open(filepath, "rb") as f: + for chunk in iter(lambda: f.read(4096), b""): + hash_md5.update(chunk) + + if hash_md5.hexdigest() != validhash: + hashMismatch = True + + + print( "\r ", end="" ) + + if hashMismatch: + print( "[" + ANSI_COLOR_RED + "hash" + ANSI_COLOR_END + "] ", end="" ) + else: + print( "[" + ANSI_COLOR_GREEN + "hash" + ANSI_COLOR_END + "] ", end="" ) + + + if BIN_VALGRIND != "": + if valgrindError: + print( "[" + ANSI_COLOR_RED + "leak" + ANSI_COLOR_END + "] ", end="" ) + else: + print( "[" + ANSI_COLOR_GREEN + "leak" + ANSI_COLOR_END + "] ", end="" ) + + + print( ANSI_COLOR_CYAN + aafFileName + ANSI_COLOR_END ) + + + if valgrindError or hashMismatch: + print( " :: Test command : " + testCmd ) + errorCounts+=1 + + if valgrindError: + print( " :: valgrind log : " + valgrindOutputFile ) + + # if errorCounts and args.run_from_cmake: + # sys.exit(errorCounts); + + + +def update( aafFileName, aaftoolAddCmd ): + + print( " [....] " + ANSI_COLOR_ORANGE + aafFileName + ANSI_COLOR_END, end="" ) + + aafFile = TEST_AAF_DIR + DIR_SEP + aafFileName; + expectedAaftoolOutputFile = TEST_EXPECTED_DIR + DIR_SEP + aafFileName + ".expected" + + if not os.path.isfile(aafFile): + print( " : " + ANSI_COLOR_RED + "Missing AAF file \"" + aafFile + "\"" + ANSI_COLOR_END ) + return + + testCmd = AAFTOOL_CMD + " " + aaftoolAddCmd + " \"" + aafFile + "\" --verb 0 --no-color --relative-path --log-file \"" + expectedAaftoolOutputFile + "\"" + + proc = subprocess.run( testCmd, capture_output=True, shell=True, text=True ) + + print( "\r [" + ANSI_COLOR_GREEN + " ok " + ANSI_COLOR_END + "] " + ANSI_COLOR_ORANGE + aafFileName + ANSI_COLOR_END ) + + + +# sys.exit(errorCounts); + + + + + +print("") + +test("MC_Empty.aaf", "") +test("DR_Empty.aaf", "") + +test("MC_Markers.aaf", "") +test("DR_Markers.aaf", "") +test("MC_Metadata.aaf", "") + +test("MC_Clip_Mute.aaf", "") +test("MC_Track_Solo_Mute.aaf", "") + +test("MC_Fades.aaf", "") +test("PR_Fades.aaf", "") +test("PT_Fades.aaf", "") +test("PT_Fades_A.aaf", "--pt-remove-sae") +test("PT_Fades_B.aaf", "--pt-true-fades") +test("PT_Fades_no_handles.aaf", "") + +test("PT_Audio_Levels-noEMCC-noExpTracksAsMultiChannel.aaf", "") +test("MC_Audio_Levels.aaf", "") # verify AAFUsage_SubClip and AAFUsage_AdjustedClip +test("PR_Audio_Levels-noBTM.aaf", "") +test("DR_Audio_Levels.aaf", "") + +test("PR_Audio_Pan-noBTM.aaf", "") +test("MC_Audio_Pan.aaf", "") + +test("MC_Audio_Warp.aaf", "") + +test("PT_WAV_External.aaf", "--media-location \"" + TEST_MEDIA_DIR + "\"") +test("PT_WAV_External_sub_directory.aaf", "--samplerate 44100") +test("PT_WAV_External_same_directory.aaf", "--samplerate 44100") + +test("PR_WAV_Internal.aaf", "") +test("PT_AIFF_External.aaf", "") +test("PR_AIFF_Internal.aaf", "") +test("PT_MXF_External.aaf", "") +test("PT_PCM_Internal.aaf", "--samplerate 44100") +test("DR_MP3_External.aaf", "") +test("PT_UTF8_EssencePath.aaf", "") + +test("DR_Mono_Clip_Positioning.aaf", "") +test("DR_Stereo_Clip_Positioning.aaf", "--samplerate 48000") + +test("DR_Multichannel_stereo_single_source.aaf", "--samplerate 44100") +test("PT_Multichannel_stereo_multi_source.aaf", "--pt-remove-sae") +test("DR_Multichannel_5.1_single_source.aaf", "") +test("PT_Multichannel_5.1_multi_source.aaf", "--pt-remove-sae") +test("DR_Multichannel_7.1_single_source.aaf", "") +test("PT_Multichannel_7.1_multi_source.aaf", "--pt-remove-sae") + +test("MC_TC_23.976.aaf", "--pos-format tc") +test("MC_TC_24.aaf", "--pos-format tc") +test("MC_TC_25.aaf", "--pos-format tc") +test("MC_TC_29.97_NDF.aaf", "--pos-format tc") +test("MC_TC_29.97_DF.aaf", "--pos-format tc") +test("MC_TC_30_NDF.aaf", "--pos-format tc") +test("MC_TC_30_DF.aaf", "--pos-format tc") +test("MC_TC_50.aaf", "--pos-format tc") +test("MC_TC_59.94_NDF.aaf", "--pos-format tc") +test("MC_TC_59.94_DF.aaf", "--pos-format tc") +test("MC_TC_60_NDF.aaf", "--pos-format tc") +test("MC_TC_60_DF.aaf", "--pos-format tc") +test("MC_TC_100.aaf", "--pos-format tc") +test("MC_TC_119.88_NDF.aaf", "--pos-format tc") +test("MC_TC_119.88_DF.aaf", "--pos-format tc") +test("MC_TC_120_NDF.aaf", "--pos-format tc") +test("MC_TC_120_DF.aaf", "--pos-format tc") + +test("PT_lang_de.aaf", "--pt-true-fades") +test("PT_lang_en.aaf", "--pt-true-fades") +test("PT_lang_es.aaf", "--pt-true-fades") +test("PT_lang_fr.aaf", "--pt-true-fades") +test("PT_lang_ja.aaf", "--pt-true-fades") +test("PT_lang_ko.aaf", "--pt-true-fades") +test("PT_lang_zh_TW.aaf", "--pt-true-fades") +test("PT_lang_zh_CN.aaf", "--pt-true-fades") + +print("") + +extract("PR_WAV_Internal.aaf", "--extract-clips --extract-format wav", [ + [ "3089dbaa3d9e03b820695504d5334d7c", "1_1_1000hz-18dbs16b44.1k.wav" ] +]) +extract("PR_WAV_Internal.aaf", "--extract-essences", [ + [ "b49538965723bb1840e01b6710da20b8", "1000hz-18dbs16b44.1k.wav" ] +]) + +extract("PR_AIFF_Internal.aaf", "--extract-clips --extract-format wav", [ + [ "44b9acf682cb12fa9c692f4e3c591079", "1_1_1000hz-18dbs16b44.1k.wav" ] +]) +extract("PR_AIFF_Internal.aaf", "--extract-essences", [ + [ "694634f1af77e1c23e76b0b41d2b223f", "1000hz-18dbs16b44.1k.wav.aif" ] +]) + +extract("PT_PCM_Internal.aaf", "--extract-clips --extract-format wav", [ + [ "2a8f46cf946e44973a4a73f84504a4c5", "1_1_1000hz-18dbs16b44.1k-01.wav" ] +]) +extract("PT_PCM_Internal.aaf", "--extract-essences --extract-format wav", [ + [ "2a8f46cf946e44973a4a73f84504a4c5", "1000hz-18dbs16b44.1k-01.wav" ] +]) + +print("") + +sys.exit(errorCounts) diff --git a/test/test.sh b/test/test.sh deleted file mode 100755 index b572270..0000000 --- a/test/test.sh +++ /dev/null @@ -1,169 +0,0 @@ -#!/bin/bash - -PROJDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd )" - -cd $PROJDIR; - -DIFF=$(which diff) -GREP=$(which grep) -VALGRIND=$(which valgrind) - -AAF_PATH="${PROJDIR}/test/aaf" -BIN_PATH="${PROJDIR}/build/bin" -EXPECTED_OUTPUT_PATH="${PROJDIR}/test/expected" -OUTPUT_PATH="${PROJDIR}/test/output" -MEDIA_PATH="${PROJDIR}/test/res" -AAFINFO_CMD="${BIN_PATH}/AAFInfo --aaf-summary --aaf-essences --aaf-clips --pos-format samples --no-color --verb 0 --media-location \"${AAF_PATH}/res\"" # --media-location \"${AAF_PATH}/res\" - -VALGRIND_CMD="$VALGRIND --error-exitcode=1 --track-origins=yes --leak-check=full --show-leak-kinds=all" -# DIFF_CMD="git diff --unified=0 --word-diff=color --minimal" -DIFF_CMD="$DIFF" - -OPT_RUN_FROM_CMAKE=0 - -if [ x"$1" = x"--run-from-cmake" ]; then - OPT_RUN_FROM_CMAKE=1 -fi - -RC=0 - - - -test() { - - printf " [....] [....] \033[38;5;81m$1\x1b[0m" - - aafFile="$AAF_PATH/$1" - expectedAAFInfoOutputFile="$EXPECTED_OUTPUT_PATH/$1.expected" - - valgrindOutputFile="$OUTPUT_PATH/$1.valgrind" - aafInfoOutputFile="$OUTPUT_PATH/$1.aafinfo" - aafInfoDiffFile="$OUTPUT_PATH/$1.aafinfodiff" - - RES_VALGRIND_ERROR=0 - RES_AAFINFO_ERROR=0 - - if [ ! -f "$aafFile" ]; then - printf " : \033[38;5;124mMissing AAF file \"$aafFile\"\x1b[0m\n" - return; - fi - - if [ ! -f "$expectedAAFInfoOutputFile" ]; then - printf " : \033[38;5;124mMissing expected-output file \"$expectedAAFInfoOutputFile\"\x1b[0m\n" - return; - fi - - - cmd="$VALGRIND_CMD --quiet --log-file=$valgrindOutputFile $AAFINFO_CMD $2 --log-file $aafInfoOutputFile $aafFile" - $cmd 2>&1>/dev/null - - if [ $? -ne 0 ]; then - RES_VALGRIND_ERROR=1 - fi - - DIFFED=$($DIFF_CMD "$expectedAAFInfoOutputFile" "$aafInfoOutputFile" | grep -vE '(\+\+\+)|(\-\-\-)|@@') #- -word-diff-regex=. - - if [ -n "$DIFFED" ]; then - RES_AAFINFO_ERROR=1 - printf "$DIFFED\n" > "$aafInfoDiffFile" - fi - - - printf "\r " - - if [ $RES_AAFINFO_ERROR -eq 1 ]; then - printf "[\033[38;5;124mdiff\x1b[0m] " - else - printf "[\x1b[92mdiff\x1b[0m] " - fi - - if [ $RES_VALGRIND_ERROR -eq 1 ]; then - printf "[\033[38;5;124mleak\x1b[0m] " - else - printf "[\x1b[92mleak\x1b[0m] " - fi - - printf "\033[38;5;81m$1\x1b[0m\n" - - - if [ $RES_AAFINFO_ERROR -eq 1 ] || [ $RES_VALGRIND_ERROR -eq 1 ]; then - printf " :: Test command : $cmd\n" - RC=1 - fi - - if [ $RES_AAFINFO_ERROR -eq 1 ]; then - printf " :: Expected : $expectedAAFInfoOutputFile\n" - printf " :: AAFInfo : $aafInfoOutputFile\n" - printf " :: Diff : $aafInfoDiffFile\n" - # else - # rm "$aafInfoOutputFile" - # rm "$aafInfoDiffFile" - fi - - if [ $RES_VALGRIND_ERROR -eq 1 ]; then - printf " :: Valgrind : $valgrindOutputFile\n" - # else - # rm "$valgrindOutputFile" - fi - - if [ $RES_AAFINFO_ERROR -eq 1 ] || [ $RES_VALGRIND_ERROR -eq 1 ]; then - printf "\n" - - if [ $OPT_RUN_FROM_CMAKE -eq 1 ]; then - exit 1 - fi - fi -} - - - -update() { - - if [ $OPT_RUN_FROM_CMAKE -eq 1 ]; then - printf "Guard: Can't update .expected files from cmake !" - exit 1 - fi - - printf " [....] \033[38;5;130m$1\x1b[0m" - - aafFile="$AAF_PATH/$1" - expectedAAFInfoOutputFile="$EXPECTED_OUTPUT_PATH/$1.expected" - - if [ ! -f "$aafFile" ]; then - printf " : \033[38;5;124mMissing AAF file \"$aafFile\"\x1b[0m\n\n" - exit 1 - fi - - $AAFINFO_CMD $2 --log-file "$expectedAAFInfoOutputFile" "$aafFile" 1>/dev/null - printf "\r [\x1b[92m ok \x1b[0m] \033[38;5;130m$1\x1b[0m\n" -} - - - -echo - -test "DR_Empty.aaf" -test "DR_Markers.aaf" - -test "PT_WAV_External.aaf" "--media-location ${MEDIA_PATH}" -test "PT_WAV_External_sub_directory.aaf" "--samplerate 44100" -test "PT_WAV_External_same_directory.aaf" "--samplerate 44100" -test "PR_WAV_Internal.aaf" -test "PT_AIFF_External.aaf" -test "PR_AIFF_Internal.aaf" -test "PT_MXF_External.aaf" -test "PT_PCM_Internal.aaf" "--samplerate 44100" -test "DR_MP3_External.aaf" -test "DR_Mono_Clip_Positioning.aaf" -test "DR_Stereo_Clip_Positioning.aaf" "--samplerate 48000" -test "DR_Multichannel_stereo_single_source.aaf" "--samplerate 44100" -test "DR_Multichannel_5.1_single_source.aaf" -test "DR_Multichannel_7.1_single_source.aaf" -test "PT_Multichannel_stereo_multi_source.aaf" -test "PT_Multichannel_5.1_multi_source.aaf" -test "PT_Multichannel_7.1_multi_source.aaf" -test "PR_Fades.aaf" - -echo - -exit $RC diff --git a/test/units/common.h b/test/units/common.h new file mode 100644 index 0000000..0f9976a --- /dev/null +++ b/test/units/common.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2017-2024 Adrien Gesta-Fline + * + * This file is part of libAAF. + * + * 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 _WIN32 + #include + #include // _O_U8TEXT +#endif + +#include +#include + +#define TEST_ERROR_STR "\x1b[38;5;242m%05i "TREE_LINE" \x1b[0m[\x1b[38;5;124mer\x1b[0m] " +#define TEST_PASSED_STR "\x1b[38;5;242m%05i "TREE_LINE" \x1b[0m[\x1b[92mok\x1b[0m] " + + + +#ifdef _WIN32 + #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING + #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 + #endif + + #define INIT_WINDOWS_CONSOLE() \ + HANDLE hOut = GetStdHandle( STD_OUTPUT_HANDLE );\ + DWORD dwMode = 0;\ + GetConsoleMode( hOut, &dwMode );\ + SetConsoleMode( hOut, (dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING) );\ + SetConsoleOutputCP(65001);\ + _setmode( _fileno(stdout), _O_U8TEXT ); +#endif + + +#ifdef __MINGW32__ + #define WPRIws L"ls" // wchar_t* + #define WPRIs L"s" // char* + + #define SET_LOCALE() setlocale( LC_ALL, "" ); + + #define TEST_LOG( ... )\ + {\ + size_t len = (size_t)snprintf( NULL, 0, __VA_ARGS__ );\ + char *str = malloc( len +1 );\ + laaf_util_snprintf_realloc( &str, &len, 0, __VA_ARGS__ );\ + wchar_t *wstr = laaf_util_windows_utf8toutf16( str );\ + fwprintf( stdout, L"%"WPRIws, wstr );\ + free( wstr );\ + } +#else + #define WPRIws L"ls" // wchar_t* + #define WPRIs L"S" // char* + + #ifdef _MSC_VER + #define SET_LOCALE() setlocale( LC_ALL, ".utf8" ); + #else + #define SET_LOCALE() setlocale( LC_ALL, "" ); + #endif + + #define TEST_LOG( ... )\ + fprintf( stdout, __VA_ARGS__ ); +#endif diff --git a/test/units/test_libtc.c b/test/units/test_libtc.c new file mode 100644 index 0000000..d2b47b8 --- /dev/null +++ b/test/units/test_libtc.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2017-2024 Adrien Gesta-Fline + * + * This file is part of libAAF. + * + * 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 "../../tools/thirdparty/libTC.h" +#include "common.h" + + +static int test_tc( int line, int32_t frameNumber, const char *tcstr, uint16_t h, uint16_t m, uint16_t s, uint16_t f, enum TC_ROLLOVER_OPT rollover, enum TC_FORMAT tcFormat ) { + + int rc = 0; + struct timecode tc; + + + tc_set_by_frames( &tc, frameNumber, tcFormat, rollover ); + + if ( tc.hours != h || + tc.minutes != m || + tc.seconds != s || + tc.frames != f ) + { + TEST_LOG( "tc_set_by_frames() @ %s error : %i %i %i %i != %i %i %i %i\n", TC_FORMAT_STR[tcFormat], tc.hours, tc.minutes, tc.seconds, tc.frames, h, m, s, f ); + rc++; + } + if ( strcmp(tc.string, tcstr) != 0 ) { + TEST_LOG( "tc_set_by_frames() @ %s error : %s != %s\n", TC_FORMAT_STR[tcFormat], tc.string, tcstr ); + rc++; + } + + + tc_set_by_hmsf( &tc, h, m, s, f, tcFormat, rollover ); + + if ( tc.frameNumber != frameNumber ) { + TEST_LOG( "tc_set_by_hmsf() @ %s error : %i != %i\n", TC_FORMAT_STR[tcFormat], tc.frameNumber, frameNumber ); + rc++; + } + if ( strcmp(tc.string, tcstr) != 0 ) { + TEST_LOG( "tc_set_by_hmsf() @ %s error : %s != %s\n", TC_FORMAT_STR[tcFormat], tc.string, tcstr ); + rc++; + } + + + tc_set_by_string( &tc, tcstr, tcFormat, rollover ); + + if ( tc.frameNumber != frameNumber ) { + TEST_LOG( "tc_set_by_string() @ %s error : %i != %i\n", TC_FORMAT_STR[tcFormat], tc.frameNumber, frameNumber ); + rc++; + } + if ( tc.hours != h || + tc.minutes != m || + tc.seconds != s || + tc.frames != f ) + { + TEST_LOG( "tc_set_by_string() @ %s error : %i %i %i %i != %i %i %i %i\n", TC_FORMAT_STR[tcFormat], tc.hours, tc.minutes, tc.seconds, tc.frames, h, m, s, f ); + rc++; + } + + + TEST_LOG( TEST_PASSED_STR "%s\n", line, TC_FORMAT_STR[tcFormat] ); + + return rc; +} + + + +int main( int argc, char *argv[] ) { + + (void)argc; + (void)argv; + +#ifdef _WIN32 + INIT_WINDOWS_CONSOLE() +#endif + + SET_LOCALE() + + int errors = 0; + + TEST_LOG("\n"); + + errors += test_tc( __LINE__, 86640, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_23_98 ); + errors += test_tc( __LINE__, 86640, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_24 ); + errors += test_tc( __LINE__, 90250, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_25 ); + errors += test_tc( __LINE__, 108300, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_29_97_NDF ); + errors += test_tc( __LINE__, 108192, "01:00:10;00", 01,00,10,00, TC_NO_ROLLOVER, TC_29_97_DF ); + errors += test_tc( __LINE__, 108300, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_30_NDF ); + errors += test_tc( __LINE__, 108192, "01:00:10;00", 01,00,10,00, TC_NO_ROLLOVER, TC_30_DF ); + // errors += test_tc( __LINE__, xxxxxx, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_47_95 ); + // errors += test_tc( __LINE__, xxxxxx, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_48 ); + errors += test_tc( __LINE__, 180500, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_50 ); + errors += test_tc( __LINE__, 216600, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_59_94_NDF ); + errors += test_tc( __LINE__, 216384, "01:00:10;00", 01,00,10,00, TC_NO_ROLLOVER, TC_59_94_DF ); + errors += test_tc( __LINE__, 216600, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_60_NDF ); + errors += test_tc( __LINE__, 216384, "01:00:10;00", 01,00,10,00, TC_NO_ROLLOVER, TC_60_DF ); + // errors += test_tc( __LINE__, xxxxxx, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_72 ); + // errors += test_tc( __LINE__, xxxxxx, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_96 ); + errors += test_tc( __LINE__, 361000, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_100 ); + errors += test_tc( __LINE__, 433200, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_119_88_NDF ); + errors += test_tc( __LINE__, 432768, "01:00:10;00", 01,00,10,00, TC_NO_ROLLOVER, TC_119_88_DF ); + errors += test_tc( __LINE__, 433200, "01:00:10:00", 01,00,10,00, TC_NO_ROLLOVER, TC_120_NDF ); + errors += test_tc( __LINE__, 432768, "01:00:10;00", 01,00,10,00, TC_NO_ROLLOVER, TC_120_DF ); + + // errors += test_tc( __LINE__, 107892*25, "01:00:00;00", 01,00,00,00, TC_ROLLOVER, TC_29_97_DF ); + + // errors += test_tc( __LINE__, 107892*25, "25:00:00;00", 25,00,00,00, TC_NO_ROLLOVER, TC_29_97_DF ); + // errors += test_tc( __LINE__, 300, "00:00:10;00", 00,00,10,00, TC_ROLLOVER, TC_29_97_DF ); + + TEST_LOG("\n"); + + return errors; +} diff --git a/test/units/test_uri.c b/test/units/test_uri.c new file mode 100644 index 0000000..1f3ef04 --- /dev/null +++ b/test/units/test_uri.c @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2017-2024 Adrien Gesta-Fline + * + * This file is part of libAAF. + * + * 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 "../../src/AAFIface/URIParser.h" +#include "common.h" + + +static int _uri_cmp( const struct uri *a, const struct uri *b ); +static void _uri_dump_diff( struct uri *a, struct uri *b, int totalDifferencies ); +static int _uri_test( const char *uristr, enum uri_option optflags, struct uri expectedRes, int line ); + + +static int _uri_cmp( const struct uri *a, const struct uri *b ) { + + int differenciesCount = 0; + + if ( a == NULL || b == NULL ) { + return -1; + } + + if ( (strcmp((a->scheme) ? a->scheme : "", (b->scheme) ? b->scheme : "") != 0 ) ) { differenciesCount++; } + if ( (strcmp((a->userinfo) ? a->userinfo : "", (b->userinfo) ? b->userinfo : "") != 0 ) ) { differenciesCount++; } + if ( (strcmp((a->user) ? a->user : "", (b->user) ? b->user : "") != 0 ) ) { differenciesCount++; } + if ( (strcmp((a->pass) ? a->pass : "", (b->pass) ? b->pass : "") != 0 ) ) { differenciesCount++; } + if ( (strcmp((a->host) ? a->host : "", (b->host) ? b->host : "") != 0 ) ) { differenciesCount++; } + if ( (strcmp((a->path) ? a->path : "", (b->path) ? b->path : "") != 0 ) ) { differenciesCount++; } + if ( (strcmp((a->query) ? a->query : "", (b->query) ? b->query : "") != 0 ) ) { differenciesCount++; } + if ( (strcmp((a->fragment) ? a->fragment : "", (b->fragment) ? b->fragment : "") != 0 ) ) { differenciesCount++; } + if ( a->port != b->port ) { differenciesCount++; } + if ( a->scheme_t != b->scheme_t ) { differenciesCount++; } + if ( a->flags != b->flags ) { differenciesCount++; } + + return differenciesCount; +} + + + +static void _uri_dump_diff( struct uri *a, struct uri *b, int totalDifferencies ) { + + int differenciesCount = 0; + + if ( a == NULL || b == NULL ) { + return; + } + + if ( (strcmp((a->scheme) ? a->scheme : "", (b->scheme) ? b->scheme : "") != 0 ) ) { + TEST_LOG( " \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .scheme : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? TREE_ENTRY : TREE_LAST_ENTRY, a->scheme, b->scheme ); + } + if ( (strcmp((a->userinfo) ? a->userinfo : "", (b->userinfo) ? b->userinfo : "") != 0 ) ) { + TEST_LOG( " \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .userinfo : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? TREE_ENTRY : TREE_LAST_ENTRY, a->userinfo, b->userinfo ); + } + if ( (strcmp((a->user) ? a->user : "", (b->user) ? b->user : "") != 0 ) ) { + TEST_LOG( " \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .user : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? TREE_ENTRY : TREE_LAST_ENTRY, a->user, b->user ); + } + if ( (strcmp((a->pass) ? a->pass : "", (b->pass) ? b->pass : "") != 0 ) ) { + TEST_LOG( " \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .pass : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? TREE_ENTRY : TREE_LAST_ENTRY, a->pass, b->pass ); + } + if ( (strcmp((a->host) ? a->host : "", (b->host) ? b->host : "") != 0 ) ) { + TEST_LOG( " \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .host : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? TREE_ENTRY : TREE_LAST_ENTRY, a->host, b->host ); + } + if ( (strcmp((a->path) ? a->path : "", (b->path) ? b->path : "") != 0 ) ) { + TEST_LOG( " \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .path : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? TREE_ENTRY : TREE_LAST_ENTRY, a->path, b->path ); + } + if ( (strcmp((a->query) ? a->query : "", (b->query) ? b->query : "") != 0 ) ) { + TEST_LOG( " \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .query : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? TREE_ENTRY : TREE_LAST_ENTRY, a->query, b->query ); + } + if ( (strcmp((a->fragment) ? a->fragment : "", (b->fragment) ? b->fragment : "") != 0 ) ) { + TEST_LOG( " \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .fragment : \"%s\" (expected: \"%s\")\n", (++differenciesCount < totalDifferencies) ? TREE_ENTRY : TREE_LAST_ENTRY, a->fragment, b->fragment ); + } + + if ( a->port != b->port ) { + TEST_LOG( " \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .port : %i (expected: %i)\n", (++differenciesCount < totalDifferencies) ? TREE_ENTRY : TREE_LAST_ENTRY, a->port, b->port ); + } + if ( a->scheme_t != b->scheme_t ) { + TEST_LOG( " \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .scheme_t : %i (expected: %i)\n", (++differenciesCount < totalDifferencies) ? TREE_ENTRY : TREE_LAST_ENTRY, a->scheme_t, b->scheme_t ); + } + if ( a->flags != b->flags ) { + TEST_LOG( " \x1b[38;5;242m\u2502\x1b[0m \x1b[38;5;124m%s .flags : %i (expected: %i)\n", (++differenciesCount < totalDifferencies) ? TREE_ENTRY : TREE_LAST_ENTRY, a->flags, b->flags ); + } +} + + + +static int _uri_test( const char *uristr, enum uri_option optflags, struct uri expectedRes, int line ) { + + struct uri *uri = laaf_uri_parse( uristr, optflags, NULL ); + + int differenciesCount = 0; + + if ( (differenciesCount = _uri_cmp( uri, &expectedRes )) == 0 ) { + TEST_LOG( TEST_PASSED_STR "laaf_uri_parse(): %s\n", line, uristr ); + } + else { + + TEST_LOG( TEST_ERROR_STR "laaf_uri_parse(): %s\n", line, uristr ); + + TEST_LOG( "\x1b[38;5;124m"); // red + _uri_dump_diff( uri, &expectedRes, differenciesCount ); + TEST_LOG( "\x1b[0m"); + + TEST_LOG( " \x1b[38;5;242m\u2502\x1b[0m\n"); + } + + laaf_uri_free(uri); + + return differenciesCount; +} + + + +int main( int argc, char *argv[] ) { + + (void)argc; + (void)argv; + +#ifdef _WIN32 + INIT_WINDOWS_CONSOLE() +#endif + + SET_LOCALE() + + TEST_LOG("\n"); + + int errors = 0; + +#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" + + errors += _uri_test( "", URI_OPT_NONE, (struct uri){ .scheme = NULL, .scheme_t = URI_SCHEME_T_UNKNOWN, .host = NULL, .port = 0, .path = NULL, .query = NULL, .fragment = NULL }, __LINE__ ); + errors += _uri_test( "https://www.server.com/PT_UTF-8_%D8%A7%D9%84%D9%81%D9%88%D8%B6%D9%89.aaf", URI_OPT_DECODE_ALL, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/PT_UTF-8_الفوضى.aaf", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://user:pass@www.server.com", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .userinfo = "user:pass", .user = "user", .pass = "pass", .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "HTTPS://www.server.com", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "hTtPs://www.server.com", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com:8080", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 8080, .path = NULL, .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com:8080?foo=bar", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 8080, .path = NULL, .query = "foo=bar", .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com:8080#anchor", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 8080, .path = NULL, .query = NULL, .fragment = "anchor", .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com/", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com/?foo=bar", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = "foo=bar", .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com/////?foo=bar", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = "foo=bar", .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com///////", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com?foo=bar", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = "foo=bar", .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com#anchor", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = NULL, .query = NULL, .fragment = "anchor", .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com/path/to/file.html?foo=bar&foo2=bar2#anchor", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/path/to/file.html", .query = "foo=bar&foo2=bar2", .fragment = "anchor", .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com:80/", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 80, .path = "/", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com:/", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com:", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + + errors += _uri_test( "https://[8:3:1:2:1234:5678::]:8080/ipv6", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "8:3:1:2:1234:5678::", .port = 8080, .path = "/ipv6", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 }, __LINE__ ); + errors += _uri_test( "https://[2001:db8:0:85a3::ac1f:8001]:8080/ipv6", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "2001:db8:0:85a3::ac1f:8001", .port = 8080, .path = "/ipv6", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 }, __LINE__ ); + errors += _uri_test( "https://user:pass@[2001:db8:3333:4444:5555:6666:1.2.3.4]:8080/ipv6", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .userinfo = "user:pass", .user = "user", .pass = "pass", .host = "2001:db8:3333:4444:5555:6666:1.2.3.4", .port = 8080, .path = "/ipv6", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 }, __LINE__ ); + errors += _uri_test( "https://192.168.0.1:8080/ipv4", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "192.168.0.1", .port = 8080, .path = "/ipv4", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV4 }, __LINE__ ); + errors += _uri_test( "https://127.0.0.1:8080/ipv4loopback", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "127.0.0.1", .port = 8080, .path = "/ipv4loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV4 | URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "https://localhost:8080/loopback", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "localhost", .port = 8080, .path = "/loopback", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "https://[0:0:0:0:0:0:0:1]:8080/ipv6loopback", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "0:0:0:0:0:0:0:1", .port = 8080, .path = "/ipv6loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 | URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "https://[::0:0:0:1]:8080/ipv6loopback", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "::0:0:0:1", .port = 8080, .path = "/ipv6loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 | URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "https://[::0:0000:0:001]:8080/ipv6loopback", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "::0:0000:0:001", .port = 8080, .path = "/ipv6loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 | URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "https://[::1]:8080/ipv6loopback", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "::1", .port = 8080, .path = "/ipv6loopback", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV6 | URI_T_LOCALHOST }, __LINE__ ); + + errors += _uri_test( "https://user:pass@192.168.0.1:8080/ipv4", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .userinfo = "user:pass", .user = "user", .pass = "pass", .host = "192.168.0.1", .port = 8080, .path = "/ipv4", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV4 }, __LINE__ ); + + errors += _uri_test( "file://///C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme = "file", .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "file:C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme = "file", .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "file:/C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme = "file", .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "file:///C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme = "file", .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "file://?/C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme = "file", .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "file://./C:/windows/path", URI_OPT_NONE, (struct uri){ .scheme = "file", .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/windows/path", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); + + // Examples from AAF files external essences + errors += _uri_test( "file:///C:/Users/username/Downloads/441-16b.wav", URI_OPT_NONE, (struct uri){ .scheme = "file", .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/Users/username/Downloads/441-16b.wav", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "file://?/E:/ADPAAF/Sequence A Rendu.mxf", URI_OPT_NONE, (struct uri){ .scheme = "file", .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "E:/ADPAAF/Sequence A Rendu.mxf", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "file:////C:/Users/username/Desktop/TEST2977052.aaf", URI_OPT_NONE, (struct uri){ .scheme = "file", .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "C:/Users/username/Desktop/TEST2977052.aaf", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "file://localhost/Users/username/Music/fonk_2_3#04.wav", URI_OPT_NONE, (struct uri){ .scheme = "file", .scheme_t = URI_SCHEME_T_FILE, .host = "localhost", .port = 0, .path = "/Users/username/Music/fonk_2_3#04.wav", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); + errors += _uri_test( "file://10.87.230.71/mixage/DR2/Avid MediaFiles/MXF/1/3572607.mxf", URI_OPT_NONE, (struct uri){ .scheme = "file", .scheme_t = URI_SCHEME_T_FILE, .host = "10.87.230.71", .port = 0, .path = "/mixage/DR2/Avid MediaFiles/MXF/1/3572607.mxf", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_IPV4 }, __LINE__ ); + errors += _uri_test( "file:///_system/Users/username/pt2MCCzmhsFRHQgdgsTMQX.mxf", URI_OPT_NONE, (struct uri){ .scheme = "file", .scheme_t = URI_SCHEME_T_FILE, .host = NULL, .port = 0, .path = "/_system/Users/username/pt2MCCzmhsFRHQgdgsTMQX.mxf", .query = NULL, .fragment = NULL, .flags = URI_T_LOCALHOST }, __LINE__ ); + + // URL Percent Decoding + errors += _uri_test( "https://www.server.com/NON_DECODING/%C2%B0%2B%29%3D%C5%93%21%3A%3B%2C%3F.%2F%C2%A7%C3%B9%2A%24%C2%B5%C2%A3%7D%5D%E2%80%9C%23%7B%5B%7C%5E%40%5D%3C%3E", URI_OPT_NONE, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/NON_DECODING/%C2%B0%2B%29%3D%C5%93%21%3A%3B%2C%3F.%2F%C2%A7%C3%B9%2A%24%C2%B5%C2%A3%7D%5D%E2%80%9C%23%7B%5B%7C%5E%40%5D%3C%3E", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com/DECODING/%C2%B0%2B%29%3D%C5%93%21%3A%3B%2C%3F.%2F%C2%A7%C3%B9%2A%24%C2%B5%C2%A3%7D%5D%E2%80%9C%23%7B%5B%7C%5E%40%5D%3C%3E", URI_OPT_DECODE_ALL, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .host = "www.server.com", .port = 0, .path = "/DECODING/°+)=œ!:;,?./§ù*$µ£}]“#{[|^@]<>", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + errors += _uri_test( "https://www.server.com/DECODING_UTF8/%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E7%B2%BE%E5%BA%A6%E7%B7%A8%E9%9B%86", URI_OPT_DECODE_ALL, (struct uri){ .scheme = "https", .scheme_t = URI_SCHEME_T_HTTPS, .userinfo = NULL, .user = NULL, .pass = NULL, .host = "www.server.com", .port = 0, .path = "/DECODING_UTF8/サンプル精度編集", .query = NULL, .fragment = NULL, .flags = URI_T_HOST_REGNAME }, __LINE__ ); + + // Examples from https://en.wikipedia.org/wiki/Uniform_Resource_Identifier + errors += _uri_test( "tel:+1-816-555-1212", URI_OPT_NONE, (struct uri){ .scheme = "tel", .scheme_t = URI_SCHEME_T_TEL, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = "+1-816-555-1212", .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ ); + errors += _uri_test( "mailto:John.Doe@example.com", URI_OPT_NONE, (struct uri){ .scheme = "mailto", .scheme_t = URI_SCHEME_T_MAILTO, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = "John.Doe@example.com", .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ ); + errors += _uri_test( "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", URI_OPT_NONE, (struct uri){ .scheme = "urn", .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = "oasis:names:specification:docbook:dtd:xml:4.1.2", .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ ); + errors += _uri_test( "ldap://[2001:db8::7]/c=GB?objectClass?one", URI_OPT_NONE, (struct uri){ .scheme = "ldap", .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = "2001:db8::7", .port = 0, .path = "/c=GB", .query = "objectClass?one", .fragment = NULL, .flags = URI_T_HOST_IPV6 }, __LINE__ ); + errors += _uri_test( "news:comp.infosystems.www.servers.unix", URI_OPT_NONE, (struct uri){ .scheme = "news", .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = "comp.infosystems.www.servers.unix", .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ ); + + // errors += _uri_test( "xxxxxxxx", URI_OPT_NONE, (struct uri){ .scheme = NULL, .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ ); + // errors += _uri_test( "xxxxxxxx", URI_OPT_NONE, (struct uri){ .scheme = NULL, .scheme_t = URI_SCHEME_T_UNKNOWN, .userinfo = NULL, .user = NULL, .pass = NULL, .host = NULL, .port = 0, .path = NULL, .query = NULL, .fragment = NULL, .flags = 0 }, __LINE__ ); + + TEST_LOG("\n"); + + return errors; +} diff --git a/test/units/test_utils.c b/test/units/test_utils.c new file mode 100644 index 0000000..63cfc98 --- /dev/null +++ b/test/units/test_utils.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2017-2024 Adrien Gesta-Fline + * + * This file is part of libAAF. + * + * 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 "common.h" + + +#define test_build_path( line, expected, dirsep, ... ) \ +{\ + char *res = laaf_util_build_path( dirsep, __VA_ARGS__ );\ + if ( !expected ) {\ + if ( !res ) {\ + TEST_LOG( TEST_PASSED_STR "laaf_util_build_path(): \"%s\"\n", line, res );\ + } else {\ + TEST_LOG( TEST_ERROR_STR "laaf_util_build_path(): \"%s\"\n", line, res );\ + errors++;\ + }\ + } else if ( strcmp( res, expected ) == 0 ) {\ + TEST_LOG( TEST_PASSED_STR "laaf_util_build_path(): \"%s\"\n", line, res );\ + } else {\ + TEST_LOG( TEST_ERROR_STR "laaf_util_build_path(): \"%s\"\n", line, res );\ + errors++;\ + }\ +} + +static int test_relative_path( int line, const char *p1, const char *p2, const char *expected ); +static int test_clean_filename( int line, const char *fname, const char *expected ); + + + +static int test_relative_path( int line, const char *p1, const char *p2, const char *expected ) { + + int pad1len = 32; + int pad2len = 32; + + pad1len -= (p1) ? (int)laaf_util_utf8strCharLen(p1) : (int)strlen("(NULL)"); + pad2len -= (p2) ? (int)laaf_util_utf8strCharLen(p2) : (int)strlen("(NULL)"); + + char *res = laaf_util_relative_path( p1, p2 ); + + if ( expected == NULL && res != NULL ) { + TEST_LOG( TEST_ERROR_STR "laaf_util_relative_path(): \"%s\"%*s \"%s\"%*s res: %s\n", line, p1, pad1len, " ", p2, pad2len, " ", res ); + return 1; + } + + if ( expected && !res ) { + TEST_LOG( TEST_ERROR_STR "laaf_util_relative_path(): \"%s\"%*s \"%s\"%*s res: (NULL)\n", line, p1, pad1len, " ", p2, pad2len, " " ); + return 1; + } + + if ( res && strcmp( res, expected ) != 0 ) { + TEST_LOG( TEST_ERROR_STR "laaf_util_relative_path(): \"%s\"%*s \"%s\"%*s res: %s\n", line, p1, pad1len, " ", p2, pad2len, " ", res ); + return 1; + } + + TEST_LOG( TEST_PASSED_STR "laaf_util_relative_path(): \"%s\"%*s \"%s\"%*s res: %s\n", line, p1, pad1len, " ", p2, pad2len, " ", res ); + + free( res ); + return 0; +} + + + +static int test_clean_filename( int line, const char *fname, const char *expected ) { + + char buf[1024]; + int pad1len = 32; + + pad1len -= (fname) ? (int)laaf_util_utf8strCharLen(fname) : (int)strlen("(NULL)"); + + if ( fname ) { + snprintf( buf, sizeof(buf), "%s", fname ); + } + + char *res = laaf_util_clean_filename( (fname) ? buf : NULL ); + + if ( expected == NULL && res != NULL ) { + TEST_LOG( TEST_ERROR_STR "laaf_util_clean_filename(): \"%s\"%*s res: \"%s\"\n", line, fname, pad1len, " ", res ); + return 1; + } + + if ( expected && !res ) { + TEST_LOG( TEST_ERROR_STR "laaf_util_clean_filename(): \"%s\"%*s res: \"(NULL)\"\n", line, fname, pad1len, " " ); + return 1; + } + + if ( res && strcmp( res, expected ) != 0 ) { + TEST_LOG( TEST_ERROR_STR "laaf_util_clean_filename(): \"%s\"%*s res: \"%s\"\n", line, fname, pad1len, " ", res ); + return 1; + } + + TEST_LOG( TEST_PASSED_STR "laaf_util_clean_filename(): \"%s\"%*s res: \"%s\"\n", line, fname, pad1len, " ", res ); + + return 0; +} + + + +static int test_is_fileext( int line, const char *filepath, const char *ext, int expected ) { + + int pad1len = 32; + pad1len -= (filepath) ? (int)laaf_util_utf8strCharLen(filepath) : (int)strlen("(NULL)"); + + + int res = laaf_util_is_fileext( filepath, ext ); + + if ( expected != res ) { + TEST_LOG( TEST_ERROR_STR "laaf_util_is_fileext(): \"%s\"%*s \"%s\"\n", line, filepath, pad1len, " ", ext ); + return 1; + } + + TEST_LOG( TEST_PASSED_STR "laaf_util_is_fileext(): \"%s\"%*s \"%s\"\n", line, filepath, pad1len, " ", ext ); + return 0; +} + + + +int main( int argc, char *argv[] ) { + + (void)argc; + (void)argv; + +#ifdef _WIN32 + INIT_WINDOWS_CONSOLE() +#endif + + SET_LOCALE() + + + int errors = 0; + + TEST_LOG("\n"); + + errors += test_clean_filename( __LINE__, NULL, NULL ); + errors += test_clean_filename( __LINE__, "", NULL ); + errors += test_clean_filename( __LINE__, " ", NULL ); + errors += test_clean_filename( __LINE__, ".", NULL ); + errors += test_clean_filename( __LINE__, "abc ", "abc" ); + errors += test_clean_filename( __LINE__, "abc.", "abc" ); + errors += test_clean_filename( __LINE__, "a bc", "a bc" ); + errors += test_clean_filename( __LINE__, " abc", " abc" ); + errors += test_clean_filename( __LINE__, "/<>:\"|?*\\ ", "_________" ); + errors += test_clean_filename( __LINE__, "サンプル", "サンプル" ); + + TEST_LOG("\n"); + + test_build_path( __LINE__, "a/b/c", "/", "a", "b", "c", NULL ); + test_build_path( __LINE__, "/a/b/c", "/", "/a", "b", "c", NULL ); + test_build_path( __LINE__, "/a/b/c", "/", "/", "a", "b", "c", NULL ); + test_build_path( __LINE__, "/a/b/c", "/", "///", "///a///", "///b///", "///c///", NULL ); + test_build_path( __LINE__, "/a/b/c/", "/", "/", "a", "b", "c", "/", NULL ); + test_build_path( __LINE__, "/サ/ン/ル", "/", "/", "サ", "ン", "ル", NULL ); + + TEST_LOG("\n"); + + test_is_fileext( __LINE__, "", "", 0 ); + test_is_fileext( __LINE__, "a", "", 0 ); + test_is_fileext( __LINE__, NULL, NULL, 0 ); + test_is_fileext( __LINE__, "a.ext", "ext", 1 ); + test_is_fileext( __LINE__, "a.ext", "EXT", 1 ); + test_is_fileext( __LINE__, "/a/b/c/d.ext", "ext", 1 ); + test_is_fileext( __LINE__, ".ext", "ext", 1 ); + test_is_fileext( __LINE__, "ル.ext", "ext", 1 ); + test_is_fileext( __LINE__, "a.ン", "ン", 1 ); + + TEST_LOG("\n"); + + errors += test_relative_path( __LINE__, NULL, NULL, NULL ); + errors += test_relative_path( __LINE__, "", "", NULL ); + errors += test_relative_path( __LINE__, "", "/a", NULL ); + errors += test_relative_path( __LINE__, "/a", "", NULL ); + errors += test_relative_path( __LINE__, "/a/b/c/file.ext", "/a", "./b/c/file.ext" ); + errors += test_relative_path( __LINE__, "/a/b/c/file.ext", "/a/b/c/d/e/", "../../file.ext" ); + errors += test_relative_path( __LINE__, "///a///b///c///file.ext", "//a///b/c////d/e/////", "../../file.ext" ); + errors += test_relative_path( __LINE__, "/file.ext", "/a/", "../file.ext" ); + errors += test_relative_path( __LINE__, "file.ext", "/a/", NULL ); + errors += test_relative_path( __LINE__, "/a", "/a", "./" ); + errors += test_relative_path( __LINE__, "/a/b", "/c/d", "../../a/b" ); + errors += test_relative_path( __LINE__, "C:/a/b", "C:\\c/d", "../../a/b" ); + errors += test_relative_path( __LINE__, "C:/a/b", "c:\\c/d", "../../a/b" ); + errors += test_relative_path( __LINE__, "C:/a/b", "D:/c/d", NULL ); + errors += test_relative_path( __LINE__, "C:/a/b", "/c/d", NULL ); + errors += test_relative_path( __LINE__, "/a/b", "c:/c/d", NULL ); + errors += test_relative_path( __LINE__, "c:/a/サンプル", "c:/c/", "../a/サンプル" ); + + TEST_LOG("\n"); + + return errors; +} diff --git a/tools/AAFExtract.c b/tools/AAFExtract.c deleted file mode 100644 index 3aea453..0000000 --- a/tools/AAFExtract.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2017-2023 Adrien Gesta-Fline - * - * This file is part of libAAF. - * - * 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 - -#ifdef _MSC_VER - #include "win/getopt.h" -#else - #include -#endif - -#include -#include // ANSI colors, laaf_util_c99strdup() - -#include "common.h" - - -static void showHelp( void ) { - printf( - "Usage: AAFExtract [options] --output-path [AAFFILE]\n" - "\n" - " --output-path Where audio files will be extracted.\n" - " --no-nonlatin If internal audio filename contains non-latin characters,\n" - " extracted file will be named out of its UUID.\n" - "\n" - " --trace Prints AAF class/object tree.\n" - "\n" - " --no-color Disable ANSI colors in output.\n" - " --verb 0=quiet 1=error 2=warning 3=debug.\n" - - "\n\n" - ); -} - -int main( int argc, char *argv[] ) -{ - setlocale( LC_ALL, "" ); - - int rc = 0; - int no_nonlatin = 0; - char *output_path = NULL; - int ansicolor = 1; - AAF_Iface *aafi = NULL; - int trace = 0; - enum verbosityLevel_e verb = VERB_WARNING; - - - const char* optstring = "hontc:v:"; - - const struct option longopts[] = { - - { "output-path", required_argument, 0, 'o' }, - { "no-nonlatin", no_argument, 0, 'n' }, - - { "trace", no_argument, 0, 't' }, - - { "no-color", no_argument, 0, 'c' }, - { "verb", required_argument, 0, 'v' }, - - { "help", no_argument, 0, 'h' }, - }; - - int c = 0; - int optindex = 0; - - while ( EOF != (c = getopt_long( argc, argv, optstring, longopts, &optindex )) ) { - - switch (c) { - - case 'o': output_path = laaf_util_c99strdup(optarg); break; - case 'n': no_nonlatin = 1; break; - - case 't': trace = 1; break; - - case 'c': ansicolor = 0; break; - case 'v': verb = atoi(optarg); break; - - case 'h': showHelp(); goto end; - - default: - printf( "Try 'AAFExtract --help' for more informations.\n" ); - return 1; - } - } - - if ( verb ) - printf( "\nAAFExtract\nlibAAF %s\n\n", LIBAAF_VERSION ); - - - if ( optind == argc ) { - - if ( verb ) - fprintf( stderr, - "Command line error: missing AAF file\n" - "Try 'AAFExtract --help' for more informations.\n" ); - - goto err; - } - - if ( output_path == NULL ) { - - if ( verb ) - fprintf( stderr, - "Command line error: missing --output-path\n" - "Try 'AAFExtract --help' for more informations.\n" ); - - goto err; - } - - - aafi = aafi_alloc( NULL ); - - if ( !aafi ) { - fprintf( stderr, "Failed to init AAF_Iface context.\n" ); - goto err; - } - - aafi_set_debug( aafi, verb, ansicolor, stdout, NULL, NULL ); - - aafi_set_option_int( aafi, "trace", trace ); - aafi_set_option_int( aafi, "forbid_nonlatin_filenames", no_nonlatin ); - - enable_windows_VT100_output(); - - - if ( aafi_load_file( aafi, argv[argc-1] ) ) { - goto err; - } - - - aafiAudioEssence *audioEssence = NULL; - - foreachEssence( audioEssence, aafi->Audio->Essences ) { - - if ( audioEssence->is_embedded ) { - if ( aafi_extract_audio_essence( aafi, audioEssence, output_path, NULL ) == 0 ) { - if ( verb ) - printf( " Audio file extracted to %ls\n", audioEssence->usable_file_path ); - } else { - /* error was already printed by library */ - } - } - } - - if ( verb ) - printf( "\nCompleted.\n\n" ); - - goto end; - -err: - rc = -1; - -end: - - if ( aafi ) - aafi_release( &aafi ); - - if ( output_path ) - free( output_path ); - - return rc; -} diff --git a/tools/AAFInfo.c b/tools/AAFInfo.c deleted file mode 100644 index 6144a31..0000000 --- a/tools/AAFInfo.c +++ /dev/null @@ -1,861 +0,0 @@ -/* - * Copyright (C) 2017-2023 Adrien Gesta-Fline - * - * This file is part of libAAF. - * - * 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 - -#ifdef _MSC_VER - #include "win/getopt.h" -#else - #include -#endif - -#include -#include // ANSI colors, laaf_util_c99strdup() - -#include "./thirdparty/libTC.h" -#include "common.h" - - -#define POS_FORMAT_BUFFER_LEN 32 - -enum pos_format { - POS_FORMAT_TC = 0, - POS_FORMAT_SAMPLES, - POS_FORMAT_HMS, - POS_FORMAT_RAW -}; - -#define INTERPOL_TO_STRING( x ) \ - (x) ? \ - (x->flags & AAFI_INTERPOL_NONE) ? "CURV_NON" : \ - (x->flags & AAFI_INTERPOL_LINEAR) ? "CURV_LIN" : \ - (x->flags & AAFI_INTERPOL_LOG) ? "CURV_LOG" : \ - (x->flags & AAFI_INTERPOL_CONSTANT) ? "CURV_CST" : \ - (x->flags & AAFI_INTERPOL_POWER) ? "CURV_PWR" : \ - (x->flags & AAFI_INTERPOL_BSPLINE) ? "CURV_BSP" : \ - "" : "" - -#define ESSENCE_TYPE_TO_STRING( type ) \ - ( type == AAFI_ESSENCE_TYPE_PCM ) ? "PCM " : \ - ( type == AAFI_ESSENCE_TYPE_WAVE ) ? "WAVE" : \ - ( type == AAFI_ESSENCE_TYPE_AIFC ) ? "AIFC" : \ - ( type == AAFI_ESSENCE_TYPE_BWAV ) ? "BWAV" : \ - ( type == AAFI_ESSENCE_TYPE_UNK ) ? "UNK " : \ - "" - - - -static const char * gainToStr( aafiAudioGain *gain ); -static const char * panToStr( aafiAudioPan *pan ); -static void dumpVaryingValues( aafiAudioGain *Gain, FILE *logfp ); -static const char * formatPosValue( aafPosition_t pos, aafRational_t *editRate, enum pos_format posFormat, enum TC_FORMAT tcFormat, aafRational_t *samplerateRational, char *buf ); -static void showHelp( void ); - - - -static const char * gainToStr( aafiAudioGain *gain ) { - - static char str[32]; - - if ( gain == NULL ) { - return "none "; - } - else - if ( gain->flags & AAFI_AUDIO_GAIN_CONSTANT ) { - snprintf( str, 32, "%+05.1lf dB", 20 * log10( aafRationalToFloat( gain->value[0] ) ) ); - return str; - } - else - if ( gain->flags & AAFI_AUDIO_GAIN_VARIABLE ) { - return "(A) "; - } - - return " wtf ? "; -} - - - -static const char * panToStr( aafiAudioPan *pan ) { - - static char str[32]; - - if ( pan == NULL ) { - return "none "; - } - else if ( pan->flags & AAFI_AUDIO_GAIN_CONSTANT ) { - - float panval = aafRationalToFloat( (*pan->value) ); - - snprintf( str, 32, "%0.1f %s ", - panval, - ( panval == 0.0 ) ? "(L)" : - ( panval == 0.5 ) ? "(C)" : - ( panval == 1.0 ) ? "(R)" : " " ); - return str; - } - else if ( pan->flags & AAFI_AUDIO_GAIN_VARIABLE ) { - return "(A) "; - } - - return " wtf ? "; -} - - - -/* - * NOTE : since aafiAudioPan is an alias of aafiAudioGain, the - * function can be called for both. - */ - -static void dumpVaryingValues( aafiAudioGain *Gain, FILE *logfp ) { - for ( int i = 0; i < Gain->pts_cnt; i++ ) { - fprintf( logfp, " VaryingValue: _time: %f _value: %f\n", - aafRationalToFloat( Gain->time[i] ), - aafRationalToFloat( Gain->value[i] ) ); - } -} - - - -static const char * formatPosValue( aafPosition_t pos, aafRational_t *editRate, enum pos_format posFormat, enum TC_FORMAT tcFormat, aafRational_t *samplerateRational, char *buf ) { - - struct timecode tc; - - if ( posFormat == POS_FORMAT_TC ) { - tc_set_by_unitValue( &tc, pos, (rational_t*)editRate, tcFormat ); - snprintf( buf, POS_FORMAT_BUFFER_LEN, "%s", tc.string ); - return buf; - } - else if ( posFormat == POS_FORMAT_SAMPLES ) { - snprintf( buf, POS_FORMAT_BUFFER_LEN, "%"PRIi64, laaf_util_converUnit( pos, editRate, samplerateRational ) ); - return buf; - } - else if ( posFormat == POS_FORMAT_HMS ) { - - uint64_t unitPerHour = aafRationalToFloat(*editRate) * 3600; - uint64_t unitPerMin = aafRationalToFloat(*editRate) * 60; - uint64_t unitPerSec = aafRationalToFloat(*editRate); - uint64_t unitPerMS = aafRationalToFloat(*editRate) / 1000; - - uint16_t h = (unitPerHour) ? (pos / unitPerHour) : 0; - uint16_t m = (unitPerMin) ? ((pos % unitPerHour) / unitPerMin) : 0; - uint16_t s = (unitPerSec) ? ((pos % unitPerHour % unitPerMin) / unitPerSec) : 0; - uint16_t ms = (unitPerMS) ? ((pos % unitPerHour % unitPerMin % unitPerSec) / unitPerMS) : 0; - - snprintf( buf, POS_FORMAT_BUFFER_LEN, "%02u:%02u:%02u.%03u", h, m, s, ms ); - return buf; - } - else if ( posFormat == POS_FORMAT_RAW ) { - snprintf( buf, POS_FORMAT_BUFFER_LEN, "%"PRIi64, pos ); - return buf; - } - - - return "wtf ?"; -} - - - -static void showHelp( void ) { - - printf( - "Usage: AAFInfo [analysis] [options] [AAFFILE]\n" - "\n" - " CFB Analysis :\n" - "\n" - " --cfb-header Displays the CFB Header.\n" - " --cfb-fat Displays the CFB FAT.\n" - " --cfb-minifat Displays the CFB MiniFAT.\n" - " --cfb-difat Displays the CFB DiFAT.\n" - " --cfb-nodes Displays the CFB node Tree.\n" - "\n" - " --get-node Retrieves and displays the node located at the given .\n" - "\n" - "\n" - " AAF Analysis :\n" - "\n" - " --aaf-summary Displays aaf informations from both header and identification objects.\n" - " --aaf-essences Lists aaf essences.\n" - " --aaf-clips Lists aaf clips.\n" - " --aaf-classes Lists aaf classes.\n" - " --aaf-meta Lists classes and properties from the MetaDictionary.\n" - " --aaf-properties Displays all Properties.\n" - "\n" - " --trace Prints file class/object tree.\n" - " --show-meta Prints MetaProperties for each class/object.\n" - " --dump-class Dumps aaf properties of a specific AAFClass.\n" - " --dump-class-raw Dumps raw properties of a specific AAFClass.\n" - "\n" - "\n" - " Options :\n" - "\n" - " --media-location Location of audio and video essence files.\n" - "\n" - " --samplerate Sample rate used for converting displayed position\n" - " and duration values. If not set, AAF dominant sample\n" - " rate is used.\n" - " --pos-format Position and duration display format.\n" - " --show-automation Shows track and clip automation values.\n" - "\n" - " --no-color Disable ANSI colors in output.\n" - " --log-file Save output to file instead of stdout.\n" - " --verb 0=quiet 1=error 2=warning 3=debug.\n" - "\n\n" - ); -} - - - -int main( int argc, char *argv[] ) { - - setlocale( LC_ALL, "" ); - - int rc = 0; - AAF_Data *aafd = NULL; - AAF_Iface *aafi = NULL; - - int cfb_header = 0; - int cfb_fat = 0; - int cfb_minifat = 0; - int cfb_difat = 0; - int cfb_nodes = 0; - - const char *get_node_str = NULL; - - int aaf_summary = 0; - int aaf_essences = 0; - int aaf_clips = 0; - int aaf_classes = 0; - int aaf_meta = 0; - int aaf_properties = 0; - - const char *media_location = NULL; - - aafRational_t displaySamplerate = { 0, 1 }; - enum pos_format posFormat = POS_FORMAT_TC; - int show_automation = 0; - - enum verbosityLevel_e verb = VERB_WARNING; - int trace = 0; - int trace_meta = 0; - int ansicolor = 1; - - const char *logfile = NULL; - FILE *logfp = stdout; - - const char *dump_class_aaf_properties = NULL; - const char *dump_class_raw_properties = NULL; - - int cmd = 0; - - - printf( "\nAAFInfo\nlibAAF %s\n\n", LIBAAF_VERSION ); - - - static struct option long_options[] = { - - { "help", no_argument, 0, 0xff }, - - { "cfb-header", no_argument, 0, 0x01 }, - { "cfb-fat", no_argument, 0, 0x02 }, - { "cfb-minifat", no_argument, 0, 0x03 }, - { "cfb-difat", no_argument, 0, 0x04 }, - { "cfb-nodes", no_argument, 0, 0x05 }, - - { "get-node", required_argument, 0, 0x06 }, - - { "aaf-summary", no_argument, 0, 0x10 }, - { "aaf-essences", no_argument, 0, 0x11 }, - { "aaf-clips", no_argument, 0, 0x12 }, - { "aaf-classes", no_argument, 0, 0x13 }, - { "aaf-meta", no_argument, 0, 0x14 }, - { "aaf-properties", no_argument, 0, 0x15 }, - - { "trace", no_argument, 0, 0x20 }, - { "show-meta", no_argument, 0, 0x21 }, - { "dump-class", required_argument, 0, 0x22 }, - { "dump-class-raw", required_argument, 0, 0x23 }, - - { "media-location", required_argument, 0, 0x30 }, - { "samplerate", required_argument, 0, 0x31 }, - { "pos-format", required_argument, 0, 0x32 }, - - { "show-automation", no_argument, 0, 0x33 }, - { "no-color", no_argument, 0, 0x34 }, - - { "log-file", required_argument, 0, 0x35 }, - { "verb", required_argument, 0, 0x36 }, - - { 0, 0, 0, 0x00 } - }; - - - int c = 0; - - while ( 1 ) - { - int option_index = 0; - - c = getopt_long ( argc, argv, "h", long_options, &option_index ); - - if ( c == -1 ) - break; - - switch ( c ) - { - case 0x01: cfb_header = 1; cmd++; break; - case 0x02: cfb_fat = 1; cmd++; break; - case 0x03: cfb_minifat = 1; cmd++; break; - case 0x04: cfb_difat = 1; cmd++; break; - case 0x05: cfb_nodes = 1; cmd++; break; - - case 0x06: get_node_str = optarg; cmd++; break; - - case 0x10: aaf_summary = 1; cmd++; break; - case 0x11: aaf_essences = 1; cmd++; break; - case 0x12: aaf_clips = 1; cmd++; break; - case 0x13: aaf_classes = 1; cmd++; break; - case 0x14: aaf_meta = 1; cmd++; break; - case 0x15: aaf_properties = 1; cmd++; break; - - case 0x20: trace = 1; cmd++; break; - case 0x21: trace_meta = 1; break; - case 0x22: dump_class_aaf_properties = optarg; break; - case 0x23: dump_class_raw_properties = optarg; break; - - case 0x30: media_location = optarg; break; - case 0x31: displaySamplerate.numerator = atoi(optarg); break; - case 0x32: - if ( strcmp( optarg, "tc" ) == 0 ) posFormat = POS_FORMAT_TC; - else if ( strcmp( optarg, "samples" ) == 0 ) posFormat = POS_FORMAT_SAMPLES; - else if ( strcmp( optarg, "hms" ) == 0 ) posFormat = POS_FORMAT_HMS; - else if ( strcmp( optarg, "raw" ) == 0 ) posFormat = POS_FORMAT_RAW; - else { - fprintf( stderr, - "Command line error: wrong --pos-format \n" - "Try 'AAFInfo --help' for more informations.\n" ); - goto err; - } - break; - - case 0x33: show_automation = 1; break; - case 0x34: ansicolor = 0; break; - - case 0x35: logfile = optarg; break; - case 0x36: verb = atoi(optarg); break; - - case 0xff: showHelp(); goto end; - - default: - fprintf( stderr, "Try 'AAFInfo --help' for more informations.\n" ); - break; - } - } - - - if ( optind == argc ) { - fprintf( stderr, - "Command line error: missing AAF file\n" - "Try 'AAFInfo --help' for more informations.\n" ); - - goto err; - } - - - if ( cmd == 0 ) { - fprintf( stderr, - "Command line error: at least one analysis option is required.\n" - "Try 'AAFInfo --help' for more informations.\n" ); - - goto err; - } - - - if ( verb < VERB_QUIET || verb >= MAX_VERB ) { - fprintf( stderr, - "Command line error: wrong --verb \n" - "Try 'AAFInfo --help' for more informations.\n" ); - - goto err; - } - - - aafi = aafi_alloc( NULL ); - - if ( !aafi ) { - fprintf( stderr, "Failed to init AAF_Iface context.\n" ); - goto err; - } - - aafd = aafi->aafd; - - if ( logfile ) { - logfp = fopen( logfile, "w" ); - - if ( logfp == NULL ) { - fprintf( stderr, "Failed to open logfile for writting : %s\n", logfile ); - goto err; - } - } - - aafi_set_debug( aafi, verb, ansicolor, logfp, NULL, NULL ); - - aafi_set_option_int( aafi, "trace", trace ); - aafi_set_option_int( aafi, "trace_meta", trace_meta ); - aafi_set_option_int( aafi, "protools", PROTOOLS_ALL ); - aafi_set_option_int( aafi, "resolve", RESOLVE_ALL ); - - aafi_set_option_str( aafi, "media_location", media_location ); - aafi_set_option_str( aafi, "dump_class_aaf_properties", dump_class_aaf_properties ); - aafi_set_option_str( aafi, "dump_class_raw_properties", dump_class_raw_properties ); - - enable_windows_VT100_output(); - - if ( aafi_load_file( aafi, argv[argc-1] ) ) { - fprintf( stderr, "Failed to open %s\n", argv[argc-1] ); - goto err; - } - - if ( displaySamplerate.numerator == 0 ) { - displaySamplerate.numerator = aafi->Audio->samplerate; - } - - fprintf( logfp, "\n" ); - - - if ( get_node_str != NULL ) { - - wchar_t wget_node_str[1024]; - - swprintf( wget_node_str, 1024, L"%" WPRIs, get_node_str ); - - cfbNode *node = cfb_getNodeByPath( aafd->cfbd, wget_node_str, 0 ); - - if ( node == NULL ) { - fprintf( stderr, "Could not find node at \"%s\"\n", get_node_str ); - } - else { - cfb_dump_node( aafd->cfbd, node, 0 ); - - wchar_t name[CFB_NODE_NAME_SZ]; - - cfb_w16towchar( name, node->_ab, node->_cb ); - - if ( wcsncmp( name, L"properties", 10 ) == 0 ) { - aaf_dump_nodeStreamProperties( aafd, node ); - } - else if ( node->_mse == STGTY_STREAM ) { - cfb_dump_nodeStream( aafd->cfbd, node ); - } - } - - fprintf( logfp, "\n\n" ); - } - - - if ( cfb_header ) { - cfb_dump_header( aafd->cfbd ); - } - - - if ( cfb_fat ) { - cfb_dump_FAT( aafd->cfbd ); - } - - - if ( cfb_minifat ) { - cfb_dump_MiniFAT( aafd->cfbd ); - } - - - if ( cfb_difat ) { - cfb_dump_DiFAT( aafd->cfbd ); - } - - - if ( cfb_nodes ) { - uint32_t i = 0; - cfb_dump_nodePaths( aafd->cfbd, 0, NULL, &i, NULL ); - } - - - enum TC_FORMAT tcFormat; - - if ( aafi->Timecode->fps == 30 && aafi->Timecode->drop ) { - tcFormat = TC_29_97_DF; - } - else { - tcFormat = tc_fps2format( (float)(aafi->Timecode->fps ), aafi->Timecode->drop ); - } - - - if ( aaf_summary ) { - - aaf_dump_Header( aafd ); - aaf_dump_Identification( aafd ); - - aafPosition_t compoStart = laaf_util_converUnit( aafi->compositionStart, aafi->compositionStart_editRate, aafi->compositionLength_editRate ); - - struct timecode tc_start; - struct timecode tc_end; - - tc_set_by_unitValue( &tc_end, laaf_util_converUnit( compoStart + aafi->compositionLength, aafi->compositionLength_editRate, aafi->Timecode->edit_rate ), (rational_t*)aafi->Timecode->edit_rate, tcFormat ); - tc_set_by_unitValue( &tc_start, aafi->Timecode->start, (rational_t*)aafi->Timecode->edit_rate, tcFormat ); - - fprintf( logfp, " Composition Name : %ls\n", aafi->compositionName ); - - fprintf( logfp, "\n" ); - - fprintf( logfp, " TC EditRrate : %i/%i\n", aafi->Timecode->edit_rate->numerator, aafi->Timecode->edit_rate->denominator ); - fprintf( logfp, " TC FPS : %u %s\n", aafi->Timecode->fps, (aafi->Timecode->drop) ? "DF" : "NDF" ); - - fprintf( logfp, "\n" ); - - fprintf( logfp, " Composition Start (EU) : %"PRIi64"\n", aafi->compositionStart ); - fprintf( logfp, " Composition Start (samples) : %"PRIi64"\n", laaf_util_converUnit( aafi->compositionStart, aafi->compositionStart_editRate, &displaySamplerate ) ); - fprintf( logfp, " Composition Start : %s\n", tc_start.string ); - - fprintf( logfp, "\n" ); - - fprintf( logfp, " Composition End (EU) : %"PRIi64" (EditRate: %i/%i)\n", compoStart + aafi->compositionLength, (aafi->compositionLength_editRate) ? aafi->compositionLength_editRate->numerator : 0, (aafi->compositionLength_editRate) ? aafi->compositionLength_editRate->denominator : 0 ); - fprintf( logfp, " Composition End (samples) : %"PRIi64"\n", laaf_util_converUnit( compoStart + aafi->compositionLength, aafi->compositionLength_editRate, &displaySamplerate ) ); - fprintf( logfp, " Composition End : %s\n", tc_end.string ); - - fprintf( logfp, "\n" ); - - fprintf( logfp, " Dominant Sample Rate : %"PRIi64"\n", aafi->Audio->samplerate ); - fprintf( logfp, " Dominant Sample Size : %i bits\n", aafi->Audio->samplesize ); - - if ( aafi->Comments != NULL ) { - - fprintf( logfp, "\n" ); - - fprintf( logfp, " UserComments :\n" ); - - aafiUserComment *Comment = aafi->Comments; - int i = 0; - - while ( Comment != NULL ) { - fprintf( logfp, " [%i] Name: \"%ls\" Text: \"%ls\"\n", i++, Comment->name, Comment->text ); - Comment = Comment->next; - } - } - - fprintf( logfp, "\n\n" ); - } - - - if ( aaf_classes ) { - aaf_dump_Classes( aafd ); - fprintf( logfp, "\n\n" ); - } - - - if ( aaf_meta ) { - aaf_dump_MetaDictionary( aafd ); - fprintf( logfp, "\n\n" ); - } - - - if ( aaf_properties ) { - - aafObject *Object = aafd->Objects; - - for ( Object = aafd->Objects; Object != NULL; Object = Object->nextObj ) - { - fprintf( logfp, "\n\n\n%s Object%s @ %ls\n", ANSI_COLOR_MAGENTA(aafd->dbg), ANSI_COLOR_RESET(aafd->dbg), aaf_get_ObjectPath( Object ) ); - aaf_dump_ObjectProperties( aafd, Object ); - } - - fprintf( logfp, "\n\n" ); - } - - - if ( aaf_essences ) { - - fprintf( logfp, "Media Essences :\n" - "================\n\n" ); - aafiAudioEssence *audioEssence = NULL; - - uint32_t i = 0; - - foreachEssence( audioEssence, aafi->Audio->Essences ) - { - char posFormatBuf[POS_FORMAT_BUFFER_LEN]; - - fprintf( logfp, " %s%u: Type: %s Length: %s %02u Ch - %s%u Hz - %s%u bits file: %ls file_name: %ls%s%ls%s\n", - ( i < 10 ) ? " " : ( i < 100 ) ? " " : "", i, - ESSENCE_TYPE_TO_STRING( audioEssence->type ), - formatPosValue( audioEssence->length, audioEssence->samplerateRational, posFormat, tcFormat, audioEssence->samplerateRational, posFormatBuf ), - audioEssence->channels, - ( audioEssence->samplerate >= 10000 ) ? "" : ( audioEssence->samplerate >= 1000 ) ? " " : ( audioEssence->samplerate >= 100 ) ? " " : ( audioEssence->samplerate >= 10 ) ? " " : " ", - audioEssence->samplerate, - ( audioEssence->samplerate >= 10 ) ? "" : " ", - audioEssence->samplesize, - ( audioEssence->is_embedded ) ? L"EMBEDDED" : ( audioEssence->usable_file_path ) ? audioEssence->usable_file_path : audioEssence->original_file_path, - audioEssence->file_name, - ( audioEssence->file_name && wcslen(audioEssence->file_name) == wcslen(audioEssence->unique_file_name) ) ? "" : " (", - ( audioEssence->file_name && wcslen(audioEssence->file_name) == wcslen(audioEssence->unique_file_name) ) ? L"" : audioEssence->unique_file_name, - ( audioEssence->file_name && wcslen(audioEssence->file_name) == wcslen(audioEssence->unique_file_name) ) ? "" : ")" ); - - i++; - } - - fprintf( logfp, "\n\n" ); - } - - - if ( aaf_clips ) { - - aafPosition_t sessionStart = 0; - - fprintf( logfp, "Tracks & Clips :\n" - "================\n\n" ); - - aafiVideoTrack *videoTrack = aafi->Video->Tracks; - aafiTimelineItem *videoItem = NULL; - aafiVideoClip *videoClip = NULL; - - if ( videoTrack != NULL ) { - - /* - * Composition Timecode does not always share the same edit rate as tracks and clips. - * Therefore, we need to do the conversion prior to any maths. - * For exemple, if TC is 30000/1001 and audio clips are 48000/1, then TC->start has to be converted from FPS to samples. - */ - - sessionStart = laaf_util_converUnit( aafi->compositionStart, aafi->compositionStart_editRate, videoTrack->edit_rate ); - - - fprintf( logfp, "VideoTrack %s(%u) - edit_rate %i/%i (%02.2f) - \"%ls\"\n", - (videoTrack->number < 10) ? " " : "", - videoTrack->number, - videoTrack->edit_rate->numerator, videoTrack->edit_rate->denominator, - aafRationalToFloat((*videoTrack->edit_rate)), - (videoTrack->name != NULL) ? videoTrack->name : L"" ); - - if ( videoTrack->Items ) { - - videoItem = videoTrack->Items; - videoClip = (aafiVideoClip*)videoItem->data; - - char posFormatBuf1[POS_FORMAT_BUFFER_LEN]; - char posFormatBuf2[POS_FORMAT_BUFFER_LEN]; - char posFormatBuf3[POS_FORMAT_BUFFER_LEN]; - char posFormatBuf4[POS_FORMAT_BUFFER_LEN]; - - fprintf( logfp, " VideoClip Start:%s Len:%s End:%s SrcOffset:%s SourceFile: %ls (%ls)\n", - formatPosValue( (videoClip->pos + sessionStart), videoClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf1 ), - formatPosValue( (videoClip->len), videoClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf2 ), - formatPosValue( (videoClip->pos + sessionStart + videoClip->len), videoClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf3 ), - formatPosValue( videoClip->essence_offset, videoClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf4 ), - (videoClip->Essence) ? videoClip->Essence->usable_file_path : L"", - (videoClip->Essence) ? videoClip->Essence->file_name : L"" ); - - fprintf( logfp, "\n\n\n" ); - } - } - - - aafiAudioTrack *audioTrack = NULL; - aafiTimelineItem *audioItem = NULL; - aafiAudioClip *audioClip = NULL; - - uint32_t clipCount = 0; - - foreach_audioTrack( audioTrack, aafi ) { - - /* - * Composition Timecode does not always share the same edit rate as tracks and clips. - * Therefore, we need to do the conversion prior to any maths. - * For exemple, if TC is 30000/1001 and audio clips are 48000/1, then TC->start has to be converted from FPS to samples. - */ - - sessionStart = laaf_util_converUnit( aafi->compositionStart, aafi->compositionStart_editRate, audioTrack->edit_rate ); - - - fprintf( logfp, "Track %s(%u) - %s - Gain: %s - Pan: %s - edit_rate: %i/%i (%02.2f) - \"%ls\"\n", - (audioTrack->number < 10) ? " " : "", - audioTrack->number, - (audioTrack->format == AAFI_TRACK_FORMAT_MONO) ? "MONO " : - (audioTrack->format == AAFI_TRACK_FORMAT_STEREO) ? "STEREO" : - (audioTrack->format == AAFI_TRACK_FORMAT_5_1) ? "5.1 " : - (audioTrack->format == AAFI_TRACK_FORMAT_7_1) ? "7.1 " : "Unknwn", - gainToStr( audioTrack->gain ), - panToStr( audioTrack->pan ), - audioTrack->edit_rate->numerator, audioTrack->edit_rate->denominator, - aafRationalToFloat((*audioTrack->edit_rate)), - (audioTrack->name != NULL) ? audioTrack->name : L"" ); - - if ( show_automation && audioTrack->gain != NULL && audioTrack->gain->flags & AAFI_AUDIO_GAIN_VARIABLE ) { - fprintf( logfp, "TRACK GAIN AUTOMATION : \n" ); - dumpVaryingValues( audioTrack->gain, logfp ); - } - - if ( show_automation && audioTrack->pan != NULL && audioTrack->pan->flags & AAFI_AUDIO_GAIN_VARIABLE ) { - fprintf( logfp, "TRACK PAN AUTOMATION : \n" ); - dumpVaryingValues( audioTrack->pan, logfp ); - } - - foreach_Item( audioItem, audioTrack ) { - - if ( audioItem->type == AAFI_TRANS ) { - - aafiTransition *Trans = (aafiTransition*)audioItem->data; - - char posFormatBuf[POS_FORMAT_BUFFER_LEN]; - - if ( ! ( Trans->flags & AAFI_TRANS_XFADE ) ) - continue; - - fprintf( logfp, " XFade: %s %s%s%s\n", - INTERPOL_TO_STRING( Trans ), - (Trans) ? " (" : "", - (Trans) ? formatPosValue( Trans->len, audioClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf ) : "", - (Trans) ? ")" : "" ); - continue; - } - else if ( audioItem->type == AAFI_AUDIO_CLIP ) { - - audioClip = (aafiAudioClip*)audioItem->data; - - aafiTransition *fadein = aafi_get_fadein( audioItem ); - aafiTransition *fadeout = aafi_get_fadeout( audioItem ); - - char posFormatBuf1[POS_FORMAT_BUFFER_LEN]; - char posFormatBuf2[POS_FORMAT_BUFFER_LEN]; - char posFormatBuf3[POS_FORMAT_BUFFER_LEN]; - char posFormatBuf4[POS_FORMAT_BUFFER_LEN]; - char posFormatBuf5[POS_FORMAT_BUFFER_LEN]; - char posFormatBuf6[POS_FORMAT_BUFFER_LEN]; - - fprintf( logfp, " Clip:%u%s Channel: %i Gain: %s %s GainAuto: %s Start: %s Len: %s End: %s SrcOffset: %s%s%s%s%s%s%s%s%s%s%s%s%ls%s\n", - clipCount, - ( clipCount < 10 ) ? " " : ( clipCount < 100 ) ? " " : "", - audioClip->channels, - gainToStr( audioClip->gain ), - (audioClip->mute) ? "(mute)" : " ", - (audioClip->automation) ? "(A) " : "none", - formatPosValue( (audioClip->pos + sessionStart), audioClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf1 ), - formatPosValue( (audioClip->len), audioClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf2 ), - formatPosValue( (audioClip->pos + sessionStart + audioClip->len), audioClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf3 ), - formatPosValue( audioClip->essence_offset, audioClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf4 ), - (fadein) ? " FadeIn: " : "", - INTERPOL_TO_STRING( fadein ), - (fadein) ? " (" : "", - (fadein) ? formatPosValue( fadein->len, audioClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf5 ) : "", - (fadein) ? ")" : "", - (fadeout) ? " FadeOut: " : "", - INTERPOL_TO_STRING( fadeout ), - (fadeout) ? " (" : "", - (fadeout) ? formatPosValue( fadeout->len, audioClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf6 ) : "", - (fadeout) ? ")" : "", - (audioClip->subClipName) ? " ClipName: \"" : "", - (audioClip->subClipName) ? audioClip->subClipName : L"", - (audioClip->subClipName) ? "\" " : "" ); - - aafiAudioEssencePointer *audioEssencePtr = audioClip->essencePointerList; - while ( audioEssencePtr ) { - if ( audioEssencePtr->essenceChannel ) { - fprintf( logfp, " SourceFile: [ch %i] %ls (%ls)\n", - audioEssencePtr->essenceChannel, - audioEssencePtr->essence->unique_file_name, - audioEssencePtr->essence->file_name ); - } - else { - fprintf( logfp, " SourceFile: [ch all] %ls (%ls)\n", - audioEssencePtr->essence->unique_file_name, - audioEssencePtr->essence->file_name ); - } - audioEssencePtr = audioEssencePtr->next; - } - - if ( show_automation && audioClip->automation ) { - fprintf( logfp, "CLIP GAIN AUTOMATION : \n" ); - dumpVaryingValues( audioClip->automation, logfp ); - } - - clipCount++; - } - } - - fprintf( logfp, "\n\n" ); - } - - - if ( aafi->Markers ) { - fprintf( logfp, "Markers :\n" - "=========\n\n" ); - } - - uint32_t markerCount = 0; - aafiMarker *marker = NULL; - - foreachMarker( marker, aafi ) { - - /* - * Composition Timecode does not always share the same edit rate as markers. - * Therefore, we need to do the conversion prior to any maths. - * For exemple, if TC is 30000/1001 and markers are 48000/1, then TC->start has to be converted from FPS to samples. - */ - - sessionStart = laaf_util_converUnit( aafi->compositionStart, aafi->compositionStart_editRate, marker->edit_rate ); - - char posFormatBuf1[POS_FORMAT_BUFFER_LEN]; - char posFormatBuf2[POS_FORMAT_BUFFER_LEN]; - - fprintf( logfp, " Marker[%i]: EditRate: %i/%i Start: %s Length: %s Color: #%02x%02x%02x Label: \"%ls\" Comment: \"%ls\"\n", - markerCount++, - marker->edit_rate->numerator, - marker->edit_rate->denominator, - formatPosValue( (marker->start + sessionStart), marker->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf1 ), - formatPosValue( marker->length, marker->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf2 ), - marker->RGBColor[0], - marker->RGBColor[1], - marker->RGBColor[2], - marker->name, - marker->comment ); - } - } - - - fprintf( logfp, "\n\n" ); - - goto end; - -err: - rc = -1; - -end: - - if ( aafi ) { - aafi_release( &aafi ); - } - if ( logfp != stdout ) { - fclose( logfp ); - } - - return rc; -} diff --git a/tools/AAFTool.c b/tools/AAFTool.c new file mode 100644 index 0000000..2f15626 --- /dev/null +++ b/tools/AAFTool.c @@ -0,0 +1,1484 @@ +/* + * Copyright (C) 2017-2024 Adrien Gesta-Fline + * + * This file is part of libAAF. + * + * 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 + +#ifdef _MSC_VER + #include "win/getopt.h" +#else + #include +#endif + +#ifdef __MINGW32__ +#include +#include +#endif + +#include +#include // ANSI colors, laaf_util_c99strdup() + +#include "./thirdparty/libTC.h" + + +#ifndef BIN_NAME +#define BIN_NAME "aaftool" +#endif + +#define BUILD_YEAR (__DATE__ + 7) + + +#define POS_FORMAT_BUFFER_LEN 64 +#define FLOAT_2_STR_BUFFER_LEN 12 + +enum pos_format { + POS_FORMAT_TC = 0, + POS_FORMAT_SAMPLES, + POS_FORMAT_HMS, + POS_FORMAT_RAW +}; + +#define INTERPOL_TO_STRING( x ) \ + (x) ? \ + (x->flags & AAFI_INTERPOL_NONE) ? "CURV_NON" : \ + (x->flags & AAFI_INTERPOL_LINEAR) ? "CURV_LIN" : \ + (x->flags & AAFI_INTERPOL_LOG) ? "CURV_LOG" : \ + (x->flags & AAFI_INTERPOL_CONSTANT) ? "CURV_CST" : \ + (x->flags & AAFI_INTERPOL_POWER) ? "CURV_PWR" : \ + (x->flags & AAFI_INTERPOL_BSPLINE) ? "CURV_BSP" : \ + "" : "" + +#define ESSENCE_TYPE_TO_STRING( type ) \ + ( type == AAFI_ESSENCE_TYPE_PCM ) ? "PCM " : \ + ( type == AAFI_ESSENCE_TYPE_WAVE ) ? "WAVE" : \ + ( type == AAFI_ESSENCE_TYPE_AIFC ) ? "AIFC" : \ + ( type == AAFI_ESSENCE_TYPE_BWAV ) ? "BWAV" : \ + ( type == AAFI_ESSENCE_TYPE_UNK ) ? "UNK " : \ + "" + + + +static const char * gainToStr( aafiAudioGain *gain ); +static const char * panToStr( aafiAudioPan *pan ); +static void dumpVaryingValues( AAF_Iface *aafi, aafiAudioGain *Gain, char showdb, const char *padding ); +static const char * formatPosValue( aafPosition_t pos, aafRational_t *editRate, enum pos_format posFormat, enum TC_FORMAT tcFormat, aafRational_t *samplerateRational, char *buf ); +static void showHelp( void ); + + + +#define log( log, ... ) \ + LOG_BUFFER_WRITE( log, __VA_ARGS__ ); \ + (log)->debug_callback( log, (void*)aafi, DEBUG_SRC_ID_DUMP, 0, "", "", 0, log->_msg, log->user ); + + + +static const char * float2str( char *buf, const char *format, double num ) { + + snprintf( buf, FLOAT_2_STR_BUFFER_LEN, format, num ); + + size_t buflen = strlen(buf); + + for ( size_t i = 0; i < buflen; i++ ) { + if ( buf[i] == ',' ) + buf[i] = '.'; + } + + return buf; +} + + + +static const char * gainToStr( aafiAudioGain *gain ) { + + static char str[FLOAT_2_STR_BUFFER_LEN]; + + if ( gain == NULL ) { + return "none "; + } + else + if ( gain->flags & AAFI_AUDIO_GAIN_CONSTANT ) { + return float2str( str, "%+05.1lf dB", 20 * log10(aafRationalToDouble(gain->value[0])) ); + } + else + if ( gain->flags & AAFI_AUDIO_GAIN_VARIABLE ) { + return "(A) "; + } + + return " wtf ? "; +} + + + +static const char * panToStr( aafiAudioPan *pan ) { + + static char str[FLOAT_2_STR_BUFFER_LEN]; + + if ( pan == NULL ) { + return "none "; + } + else if ( pan->flags & AAFI_AUDIO_GAIN_CONSTANT ) { + + char f2sbuf[FLOAT_2_STR_BUFFER_LEN]; + + double panval = aafRationalToDouble( (*pan->value) ); + + snprintf( str, 32, "%s %s ", + float2str( f2sbuf, "%0.2f", panval ), + ( panval == 0.0 ) ? "(L)" : + ( panval == 0.5 ) ? "(C)" : + ( panval == 1.0 ) ? "(R)" : " " ); + + return str; + } + else if ( pan->flags & AAFI_AUDIO_GAIN_VARIABLE ) { + return "(A) "; + } + + return " wtf ? "; +} + + + +/* + * NOTE : since aafiAudioPan is an alias of aafiAudioGain, the + * function can be called for both. + */ + +static void dumpVaryingValues( AAF_Iface *aafi, aafiAudioGain *Gain, char showdb, const char *padding ) { + + char f2sbuf1[FLOAT_2_STR_BUFFER_LEN]; + char f2sbuf2[FLOAT_2_STR_BUFFER_LEN]; + + for ( unsigned int i = 0; i < Gain->pts_cnt; i++ ) { + + log( aafi->log, "%s_time: %s%s%s _value: %s%s%s", + padding, + ANSI_COLOR_DARKGREY(aafi->log), + float2str( f2sbuf1, "%0.6f", aafRationalToDouble( Gain->time[i] ) ), + ANSI_COLOR_RESET(aafi->log), + ANSI_COLOR_DARKGREY(aafi->log), + float2str( f2sbuf2, "%0.6f", aafRationalToDouble( Gain->value[i] ) ), + ANSI_COLOR_RESET(aafi->log) ); + + if ( showdb ) { + log( aafi->log, " %s(%s dB)%s", + ANSI_COLOR_DARKGREY(aafi->log), + float2str( f2sbuf1, "%+05.1lf", 20 * log10( aafRationalToDouble( Gain->value[i] ) ) ), + ANSI_COLOR_RESET(aafi->log) ); + } + + log( aafi->log, "\n" ); + } +} + + + +static const char * formatPosValue( aafPosition_t pos, aafRational_t *editRate, enum pos_format posFormat, enum TC_FORMAT tcFormat, aafRational_t *samplerateRational, char *buf ) { + + struct timecode tc; + + if ( posFormat == POS_FORMAT_TC ) { + tc_set_by_unitValue( &tc, pos, (rational_t*)editRate, tcFormat, TC_NO_ROLLOVER ); + snprintf( buf, POS_FORMAT_BUFFER_LEN, "%s", tc.string ); + return buf; + } + else if ( posFormat == POS_FORMAT_SAMPLES ) { + snprintf( buf, POS_FORMAT_BUFFER_LEN, "%"PRIi64, aafi_convertUnit( pos, editRate, samplerateRational ) ); + return buf; + } + else if ( posFormat == POS_FORMAT_HMS ) { + + uint32_t unitPerHour = (uint32_t)aafRationalToDouble(*editRate) * 3600; + uint32_t unitPerMin = (uint32_t)aafRationalToDouble(*editRate) * 60; + uint32_t unitPerSec = (uint32_t)aafRationalToDouble(*editRate); + uint32_t unitPerMS = (uint32_t)aafRationalToDouble(*editRate) / 1000; + + int64_t h = (unitPerHour) ? (pos / unitPerHour) : 0; + int64_t m = (unitPerMin) ? ((pos % unitPerHour) / unitPerMin) : 0; + int64_t s = (unitPerSec) ? ((pos % unitPerHour % unitPerMin) / unitPerSec) : 0; + int64_t ms = (unitPerMS) ? ((pos % unitPerHour % unitPerMin % unitPerSec) / unitPerMS) : 0; + + snprintf( buf, POS_FORMAT_BUFFER_LEN, "%02"PRIi64":%02"PRIi64":%02"PRIi64".%03"PRIi64, h, m, s, ms ); + return buf; + } + else if ( posFormat == POS_FORMAT_RAW ) { + snprintf( buf, POS_FORMAT_BUFFER_LEN, "%"PRIi64, pos ); + return buf; + } + + return "wtf ?"; +} + + + +static size_t getLongestMetadataName( aafiMetaData *metadataList ) { + + size_t longestNameLen = 0; + + aafiMetaData *metadata = NULL; + + AAFI_foreachMetadata( metadataList, metadata ) { + if ( metadata->name && strlen(metadata->name) > longestNameLen ) + longestNameLen = strlen(metadata->name); + } + + return longestNameLen; +} + + + +static void showHelp( void ) { + + fprintf( stderr, + "usage: %s [analysis|extraction] [options] [AAFFILE]\n" + "\n" + " CFB Analysis:\n" + "\n" + " --cfb-header Display CFB Header.\n" + " --cfb-fat Display CFB FAT.\n" + " --cfb-minifat Display CFB MiniFAT.\n" + " --cfb-difat Display CFB DiFAT.\n" + " --cfb-nodes Display CFB node list.\n" + "\n" + " --cfb-node Display node located at the given .\n" + "\n" + "\n" + " AAF Analysis:\n" + "\n" + " --aaf-summary Display informations from both header and identification objects.\n" + " --aaf-essences Display retrieved AAF audio and video essences.\n" + " --aaf-clips Display retrieved AAF audio and video clips.\n" + " --aaf-classes Display classes contained in AAF file.\n" + " --aaf-meta Display classes and properties from the MetaDictionary.\n" + " --aaf-properties Display properties of all objects in file.\n" + "\n" + " --trace Display AAF class/object structure while parsing.\n" + " --dump-meta Display MetaProperties details for each parsed class containing meta properties.\n" + " --dump_tagged_value Display standard TaggedValue properties of Mobs and Components objects.\n" + " --dump-class Display aaf properties of a specific AAFClass when it is parsed.\n" + " --dump-class-raw Display raw properties of a specific AAFClass when it is parsed.\n" + "\n" + "\n" + " Embedded Media Extraction:\n" + "\n" + " --extract-essences Extract all embedded audio essences as they are stored (wav or aiff),\n" + " unless --extract-format is set. Raw PCM is extracted as wav file.\n" + " --extract-clips Extract all embedded audio clips (trimed essences) as wav files.\n" + " --extract-path Location where embedded files are extracted.\n" + " --extract-format Force extract format to wav or broadcast wav.\n" + " --extract-mobid Name extracted files with their MobID. This also prevents any non-latin\n" + " character in filename.\n" + "\n" + "\n" + " Software Specific Options:\n" + "\n" + " --pt-true-fades Replace rendered ProTools fade clips with real fades when possible,\n" + " when surrounding clips has enough handle size.\n" + " --pt-remove-sae Remove all ProTools \"sample accurate edit\" small clips.\n" + "\n" + "\n" + " Options:\n" + "\n" + " --media-location Location of external audio and video essence files.\n" + "\n" + " --samplerate Sample rate used for converting displayed position\n" + " and duration values. If not set, AAF dominant sample\n" + " rate is used.\n" + " --pos-format Position and duration display format.\n" + " --show-automation Show track and clip automation values when --aaf-clips is set.\n" + " --show-metadata Show source and clip metadata when --aaf-essences or --aaf-clips is set.\n" + "\n" + " --relative-path Prints AAF's relative essence path when --aaf-essences is set.\n" + "\n" + " --no-color Disable colored output.\n" + " --log-file Save output to file instead of stdout.\n" + "\n" + " --verb 0=quiet 1=error 2=warning 3=debug.\n" + "\n\n", BIN_NAME + ); +} + + + +int main( int argc, char *argv[] ) { + +#ifdef _WIN32 + #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING + #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 + #endif + /* enables "VT100" ANSI colors and UTF-8 console code page */ + HANDLE hOut = GetStdHandle( STD_OUTPUT_HANDLE ); + DWORD dwMode = 0; + GetConsoleMode( hOut, &dwMode ); + SetConsoleMode( hOut, (dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING) ); + SetConsoleOutputCP(65001); +#endif + +#ifdef __MINGW32__ + setlocale( LC_ALL, "" ); +#elif defined(_MSC_VER) + setlocale( LC_ALL, ".utf8" ); +#else + setlocale( LC_ALL, "" ); +#endif + + + int rc = 0; + AAF_Data *aafd = NULL; + AAF_Iface *aafi = NULL; + + int cfb_header = 0; + int cfb_fat = 0; + int cfb_minifat = 0; + int cfb_difat = 0; + int cfb_nodes = 0; + + char *get_node_str = NULL; + + int aaf_summary = 0; + int aaf_essences = 0; + int aaf_clips = 0; + int aaf_classes = 0; + int aaf_meta = 0; + int aaf_properties = 0; + + int extract_essences = 0; + int extract_clips = 0; + const char *extract_path = NULL; + int extract_format = AAFI_EXTRACT_DEFAULT; + int extract_mobid_filename = 0; + + int protools_options = 0; + + const char *media_location = NULL; + + aafRational_t displaySamplerate = { 0, 1 }; + enum pos_format posFormat = POS_FORMAT_TC; + int show_automation = 0; + int show_metadata = 0; + int relative_path = 0; + + enum verbosityLevel_e verb = VERB_WARNING; + int trace = 0; + int dump_meta = 0; + int dump_tagged_value = 0; + int ansicolor = 1; + + const char *logfile = NULL; + FILE *logfp = stdout; + + const char *dump_class_aaf_properties = NULL; + const char *dump_class_raw_properties = NULL; + + char *aafPath = NULL; + + int cmd = 0; + int cmderror = 0; + + fprintf( logfp, "\n%s Copyright (c) 2017-%s Adrien Gesta-Fline\nlibaaf %s\n\n", BIN_NAME, BUILD_YEAR, LIBAAF_VERSION ); + + + static struct option long_options[] = { + + { "help", no_argument, 0, 'h' }, + + { "cfb-header", no_argument, 0, 0x01 }, + { "cfb-fat", no_argument, 0, 0x02 }, + { "cfb-minifat", no_argument, 0, 0x03 }, + { "cfb-difat", no_argument, 0, 0x04 }, + { "cfb-nodes", no_argument, 0, 0x05 }, + + { "cfb-node", required_argument, 0, 0x06 }, + + { "aaf-summary", no_argument, 0, 0x10 }, + { "aaf-essences", no_argument, 0, 0x11 }, + { "aaf-clips", no_argument, 0, 0x12 }, + { "aaf-classes", no_argument, 0, 0x13 }, + { "aaf-meta", no_argument, 0, 0x14 }, + { "aaf-properties", no_argument, 0, 0x15 }, + + { "trace", no_argument, 0, 0x20 }, + { "dump-meta", no_argument, 0, 0x21 }, + { "dump-tagged-value", no_argument, 0, 0x22 }, + { "dump-class", required_argument, 0, 0x23 }, + { "dump-class-raw", required_argument, 0, 0x24 }, + + { "extract-essences", no_argument, 0, 0x30 }, + { "extract-clips", no_argument, 0, 0x31 }, + { "extract-path", required_argument, 0, 0x32 }, + { "extract-format", required_argument, 0, 0x33 }, + { "extract-mobid", no_argument, 0, 0x34 }, + + { "pt-true-fades", no_argument, 0, 0x40 }, + { "pt-remove-sae", no_argument, 0, 0x41 }, + + { "media-location", required_argument, 0, 0x50 }, + { "samplerate", required_argument, 0, 0x51 }, + { "pos-format", required_argument, 0, 0x52 }, + + { "show-automation", no_argument, 0, 0x53 }, + { "show-metadata", no_argument, 0, 0x54 }, + { "relative-path", no_argument, 0, 0x55 }, + + { "no-color", no_argument, 0, 0x56 }, + + { "log-file", required_argument, 0, 0x57 }, + { "verb", required_argument, 0, 0x58 }, + + { 0, 0, 0, 0x00 } + }; + + + int c = 0; + + while ( 1 ) + { + int option_index = 0; + + c = getopt_long ( argc, argv, "h", long_options, &option_index ); + + if ( c == -1 ) + break; + + switch ( c ) + { + case 0x01: cfb_header = 1; cmd++; break; + case 0x02: cfb_fat = 1; cmd++; break; + case 0x03: cfb_minifat = 1; cmd++; break; + case 0x04: cfb_difat = 1; cmd++; break; + case 0x05: cfb_nodes = 1; cmd++; break; + + case 0x06: + free( get_node_str ); + get_node_str = laaf_util_c99strdup( optarg ); + cmd++; break; + + case 0x10: aaf_summary = 1; cmd++; break; + case 0x11: aaf_essences = 1; cmd++; break; + case 0x12: aaf_clips = 1; cmd++; break; + case 0x13: aaf_classes = 1; cmd++; break; + case 0x14: aaf_meta = 1; cmd++; break; + case 0x15: aaf_properties = 1; cmd++; break; + + case 0x20: trace = 1; cmd++; break; + case 0x21: dump_meta = 1; break; + case 0x22: dump_tagged_value = 1; break; + case 0x23: dump_class_aaf_properties = optarg; break; + case 0x24: dump_class_raw_properties = optarg; break; + + case 0x30: extract_essences = 1; cmd++; break; + case 0x31: extract_clips = 1; cmd++; break; + case 0x32: extract_path = optarg; break; + case 0x33: + if ( strcmp( optarg, "wav" ) == 0 ) extract_format = AAFI_EXTRACT_WAV; + else if ( strcmp( optarg, "bwav" ) == 0 ) extract_format = AAFI_EXTRACT_BWAV; + else { + fprintf( stderr, + "Command line error: wrong --extract-format \n" + "Try '%s --help' for more informations.\n", BIN_NAME ); + goto err; + } + break; + case 0x34: extract_mobid_filename = 1; cmd++; break; + + case 0x40: protools_options |= AAFI_PROTOOLS_OPT_REPLACE_CLIP_FADES; break; + case 0x41: protools_options |= AAFI_PROTOOLS_OPT_REMOVE_SAMPLE_ACCURATE_EDIT; break; + + case 0x50: media_location = optarg; break; + case 0x51: displaySamplerate.numerator = atoi(optarg); break; + case 0x52: + if ( strcmp( optarg, "tc" ) == 0 ) posFormat = POS_FORMAT_TC; + else if ( strcmp( optarg, "samples" ) == 0 ) posFormat = POS_FORMAT_SAMPLES; + else if ( strcmp( optarg, "hms" ) == 0 ) posFormat = POS_FORMAT_HMS; + else if ( strcmp( optarg, "raw" ) == 0 ) posFormat = POS_FORMAT_RAW; + else { + fprintf( stderr, + "Command line error: wrong --pos-format \n" + "Try '%s --help' for more informations.\n", BIN_NAME ); + goto err; + } + break; + + case 0x53: show_automation = 1; break; + case 0x54: show_metadata = 1; break; + case 0x55: relative_path = 1; break; + + case 0x56: ansicolor = 0; break; + + case 0x57: logfile = optarg; break; + case 0x58: verb = atoi(optarg); break; + + case 'h': showHelp(); goto end; + + default: + cmderror++; + fprintf( stderr, "Try '%s --help' for more informations.\n", BIN_NAME ); + break; + } + } + + if ( cmderror ) { + goto err; + } + + if ( optind == argc ) { + fprintf( stderr, + "Command line error: missing AAF file\n" + "Try '%s --help' for more informations.\n", BIN_NAME ); + + goto err; + } + + + if ( cmd == 0 ) { + fprintf( stderr, + "Command line error: at least one analysis or extract option is required.\n" + "Try '%s --help' for more informations.\n", BIN_NAME ); + + goto err; + } + + + if ( !extract_path ) { + + if ( extract_clips ) { + fprintf( stderr, + "Command line error: --extract-clips requires --extract-path to be set.\n" + "Try '%s --help' for more informations.\n", BIN_NAME ); + + goto err; + } + + if ( extract_essences ) { + fprintf( stderr, + "Command line error: --extract-essences requires --extract-path to be set.\n" + "Try '%s --help' for more informations.\n", BIN_NAME ); + + goto err; + } + } + + + if ( extract_clips && extract_essences ) { + fprintf( stderr, + "Command line error: can't use --extract-clips and --extract-essences at the same time.\n" + "Try '%s --help' for more informations.\n", BIN_NAME ); + + goto err; + } + + + if ( verb < VERB_QUIET || verb >= MAX_VERB ) { + fprintf( stderr, + "Command line error: wrong --verb \n" + "Try '%s --help' for more informations.\n", BIN_NAME ); + + goto err; + } + + + aafi = aafi_alloc( NULL ); + + if ( !aafi ) { + fprintf( stderr, "Failed to init AAF_Iface context.\n" ); + goto err; + } + + aafd = aafi->aafd; + + if ( logfile ) { + logfp = fopen( logfile, "w" ); + + if ( logfp == NULL ) { + fprintf( stderr, "Failed to open logfile for writting : %s\n", logfile ); + goto err; + } + } + +#ifdef __MINGW32__ + /* mingw fails to print UTF-8 without _setmode() */ + _setmode( _fileno(logfp), _O_U8TEXT ); +#endif + + aafi_set_debug( aafi, verb, ansicolor, logfp, NULL, NULL ); + + aafi_set_option_int( aafi, "trace", trace ); + aafi_set_option_int( aafi, "dump_meta", dump_meta ); + aafi_set_option_int( aafi, "dump_tagged_value", dump_tagged_value ); + aafi_set_option_int( aafi, "protools", protools_options ); + aafi_set_option_int( aafi, "mobid_essence_filename", extract_mobid_filename ); + + aafi_set_option_str( aafi, "media_location", media_location ); + aafi_set_option_str( aafi, "dump_class_aaf_properties", dump_class_aaf_properties ); + aafi_set_option_str( aafi, "dump_class_raw_properties", dump_class_raw_properties ); + + + if ( aafi_load_file( aafi, argv[argc-1] ) ) { + fprintf( stderr, "Failed to open %s\n", argv[argc-1] ); + goto err; + } + + if ( displaySamplerate.numerator == 0 ) { + displaySamplerate.numerator = (int)aafi->Audio->samplerate; + } + + + /* use aafi->aafd->cfbd->file instead of argv[argc-1] because it is set absolute */ + aafPath = laaf_util_c99strdup( aafi->aafd->cfbd->file ); + + if ( !aafPath ) { + fprintf( stderr, "Could not duplicate AAF filepath : %s", aafi->aafd->cfbd->file ); + goto err; + } + + char *p = aafPath + strlen(aafPath); + + while ( p > aafPath ) { + if ( IS_DIR_SEP(*p) ) { + *p = 0x00; + break; + } + p--; + } + + + log( aafi->log, "\n" ); + + + if ( get_node_str != NULL ) { + + cfbNode *node = cfb_getNodeByPath( aafd->cfbd, get_node_str, 0 ); + + if ( node == NULL ) { + fprintf( stderr, "Could not find node at \"%s\"\n", get_node_str ); + } + else { + cfb_dump_node( aafd->cfbd, node, 0, " " ); + + char *name = cfb_w16toUTF8( node->_ab, node->_cb ); + + if ( strncmp( name, "properties", 10 ) == 0 ) { + aaf_dump_nodeStreamProperties( aafd, node, " " ); + } + else if ( node->_mse == STGTY_STREAM ) { + cfb_dump_nodeStream( aafd->cfbd, node, " " ); + } + + free( name ); + } + + log( aafi->log, "\n\n" ); + } + + + if ( cfb_header ) { + cfb_dump_header( aafd->cfbd, " " ); + } + + + if ( cfb_fat ) { + cfb_dump_FAT( aafd->cfbd, " " ); + } + + + if ( cfb_minifat ) { + cfb_dump_MiniFAT( aafd->cfbd, " " ); + } + + + if ( cfb_difat ) { + cfb_dump_DiFAT( aafd->cfbd, " " ); + } + + + if ( cfb_nodes ) { + uint32_t i = 0; + cfb_dump_nodePaths( aafd->cfbd, 0, NULL, &i, NULL, " ", 1 ); + } + + + enum TC_FORMAT tcFormat = tc_get_format_by_fps( aafRationalToFloat(*aafi->Timecode->edit_rate), aafi->Timecode->drop ); + + if ( tcFormat == TC_FORMAT_UNK ) { + /* + * Needed for non-SMPTE frame rates from Adobe Premiere Pro (eg. 300260000/10000000, 30.025999) + */ + tcFormat = tc_get_format_by_fps( (float)aafi->Timecode->fps, aafi->Timecode->drop ); + } + + if ( tcFormat == TC_FORMAT_UNK ) { + fprintf( stderr, "Could not set timecode format: %i (%i/%i, %f)\n", aafi->Timecode->fps, aafi->Timecode->edit_rate->numerator, aafi->Timecode->edit_rate->denominator, aafRationalToDouble(*aafi->Timecode->edit_rate) ); + goto err; + } + + + if ( aaf_summary ) { + + aaf_dump_Header( aafd, " " ); + + log( aafd->log, "\n" ); + + aaf_dump_Identification( aafd, " " ); + + log( aafd->log, "\n" ); + + aafPosition_t compoStart = aafi_convertUnit( aafi->compositionStart, aafi->compositionStart_editRate, aafi->compositionLength_editRate ); + + struct timecode tc_start; + struct timecode tc_end; + + tc_set_by_unitValue( &tc_end, aafi_convertUnit( compoStart + aafi->compositionLength, aafi->compositionLength_editRate, aafi->Timecode->edit_rate ), (rational_t*)aafi->Timecode->edit_rate, tcFormat, TC_NO_ROLLOVER ); + tc_set_by_unitValue( &tc_start, aafi->Timecode->start, (rational_t*)aafi->Timecode->edit_rate, tcFormat, TC_NO_ROLLOVER ); + + log( aafd->log, " Composition Name : %s%s%s\n", ANSI_COLOR_DARKGREY(aafi->log), aafi->compositionName, ANSI_COLOR_RESET(aafi->log) ); + + log( aafd->log, "\n" ); + + log( aafd->log, " TC EditRrate : %s%i/%i%s\n", ANSI_COLOR_DARKGREY(aafi->log), aafi->Timecode->edit_rate->numerator, aafi->Timecode->edit_rate->denominator, ANSI_COLOR_RESET(aafi->log) ); + log( aafd->log, " TC FPS : %s%u %s%s\n", ANSI_COLOR_DARKGREY(aafi->log), aafi->Timecode->fps, (aafi->Timecode->drop) ? "DF" : "NDF", ANSI_COLOR_RESET(aafi->log) ); + + log( aafd->log, "\n" ); + + log( aafd->log, " Composition Start (EU) : %s%"PRIi64"%s\n", ANSI_COLOR_DARKGREY(aafi->log), aafi->compositionStart, ANSI_COLOR_RESET(aafi->log) ); + log( aafd->log, " Composition Start (samples) : %s%"PRIi64"%s\n", ANSI_COLOR_DARKGREY(aafi->log), aafi_convertUnit( aafi->compositionStart, aafi->compositionStart_editRate, &displaySamplerate ), ANSI_COLOR_RESET(aafi->log) ); + log( aafd->log, " Composition Start : %s%s%s\n", ANSI_COLOR_DARKGREY(aafi->log), tc_start.string, ANSI_COLOR_RESET(aafi->log) ); + + log( aafd->log, "\n" ); + + log( aafd->log, " Composition End (EU) : %s%"PRIi64" (EditRate: %i/%i)%s\n", ANSI_COLOR_DARKGREY(aafi->log), compoStart + aafi->compositionLength, (aafi->compositionLength_editRate) ? aafi->compositionLength_editRate->numerator : 0, (aafi->compositionLength_editRate) ? aafi->compositionLength_editRate->denominator : 0, ANSI_COLOR_RESET(aafi->log) ); + log( aafd->log, " Composition End (samples) : %s%"PRIi64"%s\n", ANSI_COLOR_DARKGREY(aafi->log), aafi_convertUnit( compoStart + aafi->compositionLength, aafi->compositionLength_editRate, &displaySamplerate ), ANSI_COLOR_RESET(aafi->log) ); + log( aafd->log, " Composition End : %s%s%s\n", ANSI_COLOR_DARKGREY(aafi->log), tc_end.string, ANSI_COLOR_RESET(aafi->log) ); + + log( aafd->log, "\n" ); + + log( aafd->log, " Dominant Sample Rate : %s%u%s\n", ANSI_COLOR_DARKGREY(aafi->log), aafi->Audio->samplerate, ANSI_COLOR_RESET(aafi->log) ); + log( aafd->log, " Dominant Sample Size : %s%u bits%s\n", ANSI_COLOR_DARKGREY(aafi->log), aafi->Audio->samplesize, ANSI_COLOR_RESET(aafi->log) ); + + if ( aafi->metadata != NULL ) { + + log( aafd->log, "\n" ); + + log( aafd->log, " Metadata:\n" ); + + size_t longestName = getLongestMetadataName( aafi->metadata ) + 1; + + aafiMetaData *metadata = NULL; + + AAFI_foreachMetadata( aafi->metadata, metadata ) { + log( aafd->log, " - Name: %s\"%s\"%s%*s Text: %s\"%s\"%s\n", + ANSI_COLOR_DARKGREY(aafi->log), + (metadata->name) ? metadata->name : "", + ANSI_COLOR_RESET(aafi->log), + + (metadata->name) ? (int)(longestName-strlen(metadata->name)) : (int)(longestName-strlen("")), " ", + + ANSI_COLOR_DARKGREY(aafi->log), + metadata->text, + ANSI_COLOR_RESET(aafi->log) ); + } + } + + log( aafd->log, "\n\n" ); + } + + + if ( aaf_classes ) { + aaf_dump_Classes( aafd, " " ); + log( aafd->log, "\n\n" ); + } + + + if ( aaf_meta ) { + aaf_dump_MetaDictionary( aafd, " " ); + log( aafd->log, "\n\n" ); + } + + + if ( aaf_properties ) { + + aafObject *Object = NULL; + + for ( Object = aafd->Objects; Object != NULL; Object = Object->nextObj ) { + log( aafd->log, "\n\n\n Object @ %s%s%s\n", ANSI_COLOR_DARKGREY(aafd->log), aaf_get_ObjectPath( Object ), ANSI_COLOR_RESET(aafd->log) ); + aaf_dump_ObjectProperties( aafd, Object, " " ); + } + + log( aafd->log, "\n\n" ); + } + + + if ( aaf_essences ) { + + log( aafi->log, "Media Essences :\n" + "================\n\n" ); + + uint32_t essenceIndex = 1; + aafiVideoEssence *videoEssenceFile = NULL; + + AAFI_foreachVideoEssence( aafi, videoEssenceFile ) + { + char posFormatBuf[POS_FORMAT_BUFFER_LEN]; + + log( aafi->log, " Video[%u] :: Length: %s%s%s Name: %s\"%s\"%s UniqueName: %s\"%s\"%s\n", + essenceIndex, + + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( videoEssenceFile->length, &displaySamplerate, posFormat, tcFormat, &displaySamplerate, posFormatBuf ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + videoEssenceFile->name, + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + videoEssenceFile->unique_name, + ANSI_COLOR_RESET(aafi->log) ); + + char *relativeFilePath = NULL; + + if ( !videoEssenceFile->is_embedded && videoEssenceFile->usable_file_path && relative_path ) { + relativeFilePath = laaf_util_relative_path( videoEssenceFile->usable_file_path, aafPath ); + } + + log( aafi->log, " %s File: %s\"%s\"%s\n", + ( show_metadata && videoEssenceFile->metadata ) ? TREE_ENTRY : TREE_LAST_ENTRY, + ANSI_COLOR_DARKGREY(aafi->log), + ( videoEssenceFile->is_embedded ) ? "EMBEDDED" : ( videoEssenceFile->usable_file_path ) ? (( relative_path ) ? relativeFilePath : videoEssenceFile->usable_file_path ) : videoEssenceFile->original_file_path, + ANSI_COLOR_RESET(aafi->log) ); + + if ( show_metadata && videoEssenceFile->metadata != NULL ) { + + size_t longestName = getLongestMetadataName( videoEssenceFile->metadata ) + 1; + + log( aafi->log, " %s Metadata:\n", TREE_LAST_ENTRY ); + + aafiMetaData *metadata = NULL; + + AAFI_foreachMetadata( videoEssenceFile->metadata, metadata ) { + log( aafi->log, " - Name: %s\"%s\"%s%*s Text: %s\"%s\"%s\n", + ANSI_COLOR_DARKGREY(aafi->log), + (metadata->name) ? metadata->name : "", + ANSI_COLOR_RESET(aafi->log), + + (metadata->name) ? (int)(longestName-strlen(metadata->name)) : (int)(longestName-strlen("")), " ", + + ANSI_COLOR_DARKGREY(aafi->log), + metadata->text, + ANSI_COLOR_RESET(aafi->log) ); + } + } + + log( aafi->log, "\n" ); + essenceIndex++; + } + + if ( aafi->Video->essenceFiles ) { + log( aafi->log, "\n" ); + } + + + essenceIndex = 1; + aafiAudioEssenceFile *audioEssenceFile = NULL; + + AAFI_foreachAudioEssenceFile( aafi, audioEssenceFile ) { + + char posFormatBuf[POS_FORMAT_BUFFER_LEN]; + + log( aafi->log, " Audio[%u] :: Format: %s%s - %02u ch - %s%u Hz - %s%u bits%s Length: %s%s%s Name: %s\"%s\"%s UniqueName: %s\"%s\"%s\n", + essenceIndex, + + ANSI_COLOR_DARKGREY(aafi->log), + ESSENCE_TYPE_TO_STRING( audioEssenceFile->type ), + audioEssenceFile->channels, + ( audioEssenceFile->samplerate >= 10000 ) ? "" : ( audioEssenceFile->samplerate >= 1000 ) ? " " : ( audioEssenceFile->samplerate >= 100 ) ? " " : ( audioEssenceFile->samplerate >= 10 ) ? " " : " ", + audioEssenceFile->samplerate, + ( audioEssenceFile->samplerate >= 10 ) ? "" : " ", + audioEssenceFile->samplesize, + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( audioEssenceFile->length, audioEssenceFile->samplerateRational, posFormat, tcFormat, audioEssenceFile->samplerateRational, posFormatBuf ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + audioEssenceFile->name, + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + audioEssenceFile->unique_name, + ANSI_COLOR_RESET(aafi->log) ); + + + char *relativeFilePath = NULL; + + if ( !audioEssenceFile->is_embedded && audioEssenceFile->usable_file_path && relative_path ) { + relativeFilePath = laaf_util_relative_path( audioEssenceFile->usable_file_path, aafPath ); + } + + log( aafi->log, " %s File: %s\"%s\"%s\n", + ( show_metadata && audioEssenceFile->metadata ) ? TREE_ENTRY : TREE_LAST_ENTRY, + ANSI_COLOR_DARKGREY(aafi->log), + ( audioEssenceFile->is_embedded ) ? "EMBEDDED" : (( audioEssenceFile->usable_file_path ) ? (( relative_path ) ? relativeFilePath : audioEssenceFile->usable_file_path ) : audioEssenceFile->original_file_path), + ANSI_COLOR_RESET(aafi->log) ); + + free( relativeFilePath ); + + + if ( show_metadata && audioEssenceFile->metadata != NULL ) { + + size_t longestName = getLongestMetadataName( audioEssenceFile->metadata ) + 1; + + log( aafi->log, " %s Metadata:\n", TREE_LAST_ENTRY ); + + aafiMetaData *metadata = NULL; + + AAFI_foreachMetadata( audioEssenceFile->metadata, metadata ) { + log( aafi->log, " - Name: %s\"%s\"%s%*s Text: %s\"%s\"%s\n", + ANSI_COLOR_DARKGREY(aafi->log), + (metadata->name) ? metadata->name : "", + ANSI_COLOR_RESET(aafi->log), + + (metadata->name) ? (int)(longestName-strlen(metadata->name)) : (int)(longestName-strlen("")), " ", + + ANSI_COLOR_DARKGREY(aafi->log), + metadata->text, + ANSI_COLOR_RESET(aafi->log) ); + } + } + + log( aafi->log, "\n" ); + essenceIndex++; + } + + log( aafi->log, "\n" ); + } + + + if ( aaf_clips ) { + + char f2sbuf[FLOAT_2_STR_BUFFER_LEN]; + + aafPosition_t sessionStart = 0; + + log( aafi->log, "Tracks & Clips :\n" + "================\n\n" ); + + aafiVideoTrack *videoTrack = aafi->Video->Tracks; + aafiTimelineItem *videoItem = NULL; + aafiVideoClip *videoClip = NULL; + + if ( videoTrack != NULL ) { + + /* + * Composition Timecode does not always share the same edit rate as tracks and clips. + * Therefore, we need to do the conversion prior to any maths. + * For exemple, if TC is 30000/1001 and audio clips are 48000/1, then TC->start has to be converted from FPS to samples. + */ + + sessionStart = aafi_convertUnit( aafi->compositionStart, aafi->compositionStart_editRate, videoTrack->edit_rate ); + + + log( aafi->log, " VideoTrack[%u] :: EditRate: %s%i/%i (%s)%s", + videoTrack->number, + ANSI_COLOR_DARKGREY(aafi->log), + videoTrack->edit_rate->numerator, videoTrack->edit_rate->denominator, + float2str( f2sbuf, "%02.2f", aafRationalToDouble(*videoTrack->edit_rate) ), + ANSI_COLOR_RESET(aafi->log) ); + + if ( videoTrack->name && videoTrack->name[0] != 0x00 ) { + log( aafi->log, " Name: %s\"%s\"%s", + ANSI_COLOR_DARKGREY(aafi->log), + videoTrack->name, + ANSI_COLOR_RESET(aafi->log) ); + } + + log( aafi->log, "\n" ); + + if ( videoTrack->timelineItems ) { + + videoItem = videoTrack->timelineItems; + videoClip = (aafiVideoClip*)videoItem->data; + + char posFormatBuf1[POS_FORMAT_BUFFER_LEN]; + char posFormatBuf2[POS_FORMAT_BUFFER_LEN]; + char posFormatBuf3[POS_FORMAT_BUFFER_LEN]; + char posFormatBuf4[POS_FORMAT_BUFFER_LEN]; + + log( aafi->log, " %s Clip (1): Start: %s%s%s Len: %s%s%s End: %s%s%s SourceOffset: %s%s%s\n", + TREE_LAST_ENTRY, + + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( (videoClip->pos + sessionStart), videoClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf1 ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( (videoClip->len), videoClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf2 ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( (videoClip->pos + sessionStart + videoClip->len), videoClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf3 ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( videoClip->essence_offset, videoClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf4 ), + ANSI_COLOR_RESET(aafi->log) ); + + log( aafi->log, "\n" ); + } + + log( aafi->log, "\n" ); + } + + log( aafi->log, "\n" ); + + + + aafiAudioTrack *audioTrack = NULL; + aafiTimelineItem *audioItem = NULL; + + AAFI_foreachAudioTrack( aafi, audioTrack ) { + + /* + * Composition Timecode does not always share the same edit rate as tracks and clips. + * Therefore, we need to do the conversion prior to any maths. + * For exemple, if TC is 30000/1001 and audio clips are 48000/1, then TC->start has to be converted from FPS to samples. + */ + + sessionStart = aafi_convertUnit( aafi->compositionStart, aafi->compositionStart_editRate, audioTrack->edit_rate ); + + int trackLineItemCounter = 1; + int totalTrackLineItems = 0; + totalTrackLineItems += ( show_automation && audioTrack->pan != NULL && audioTrack->pan->flags & AAFI_AUDIO_GAIN_VARIABLE ) ? 1 : 0; + totalTrackLineItems += ( show_automation && audioTrack->gain != NULL && audioTrack->gain->flags & AAFI_AUDIO_GAIN_VARIABLE ) ? 1 : 0; + totalTrackLineItems += audioTrack->clipCount; + + log( aafi->log, " AudioTrack[%u] :: EditRate: %s%i/%i (%s)%s Format: %s%s%s", + audioTrack->number, + + ANSI_COLOR_DARKGREY(aafi->log), + audioTrack->edit_rate->numerator, audioTrack->edit_rate->denominator, + float2str( f2sbuf, "%02.2f", aafRationalToDouble(*audioTrack->edit_rate) ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + (audioTrack->format == AAFI_TRACK_FORMAT_MONO) ? "MONO" : + (audioTrack->format == AAFI_TRACK_FORMAT_STEREO) ? "STEREO" : + (audioTrack->format == AAFI_TRACK_FORMAT_5_1) ? "5.1" : + (audioTrack->format == AAFI_TRACK_FORMAT_7_1) ? "7.1" : "Unknwn", + ANSI_COLOR_RESET(aafi->log) ); + + if ( audioTrack->solo ) { + log( aafi->log, " Solo: %s%s%s", + ANSI_COLOR_DARKGREY(aafi->log), + "SOLO", + ANSI_COLOR_RESET(aafi->log) ); + } + + if ( audioTrack->mute ) { + log( aafi->log, " Mute: %s%s%s", + ANSI_COLOR_DARKGREY(aafi->log), + "MUTE", + ANSI_COLOR_RESET(aafi->log) ); + } + + if ( audioTrack->gain ) { + log( aafi->log, " Gain: %s%s%s", + ANSI_COLOR_DARKGREY(aafi->log), + gainToStr( audioTrack->gain ), + ANSI_COLOR_RESET(aafi->log) ); + } + + if ( audioTrack->pan ) { + log( aafi->log, " Pan: %s%s%s", + ANSI_COLOR_DARKGREY(aafi->log), + panToStr( audioTrack->pan ), + ANSI_COLOR_RESET(aafi->log) ); + } + + if ( audioTrack->name && audioTrack->name[0] != 0x00 ) { + log( aafi->log, " Name: %s\"%s\"%s", + ANSI_COLOR_DARKGREY(aafi->log), + audioTrack->name, + ANSI_COLOR_RESET(aafi->log) ); + } + + log( aafi->log, "\n" ); + + AAFI_foreachTrackItem( audioTrack, audioItem ) { + + aafiTransition *crossFade = aafi_timelineItemToCrossFade( audioItem ); + aafiAudioClip *audioClip = aafi_timelineItemToAudioClip( audioItem ); + + if ( crossFade ) { + + char posFormatBuf1[POS_FORMAT_BUFFER_LEN]; + char posFormatBuf2[POS_FORMAT_BUFFER_LEN]; + + if ( !(crossFade->flags & AAFI_TRANS_XFADE) ) + continue; + + log( aafi->log, " %s X-FADE: %s%s%s Length: %s%s%s CutPoint: %s%s%s\n", + ( trackLineItemCounter <= totalTrackLineItems ) ? TREE_ENTRY : TREE_LAST_ENTRY, + ANSI_COLOR_DARKGREY(aafi->log), + INTERPOL_TO_STRING( crossFade ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( crossFade->len, audioTrack->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf1 ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( crossFade->cut_pt, audioTrack->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf2 ), + ANSI_COLOR_RESET(aafi->log) ); + + log( aafi->log, " %s\n", ( trackLineItemCounter <= totalTrackLineItems ) ? TREE_LINE : " " ); + continue; + } + else if ( audioClip ) { + + aafiTransition *fadein = aafi_getFadeIn( audioClip ); + aafiTransition *fadeout = aafi_getFadeOut( audioClip ); + + char posFormatBuf1[POS_FORMAT_BUFFER_LEN]; + char posFormatBuf2[POS_FORMAT_BUFFER_LEN]; + char posFormatBuf3[POS_FORMAT_BUFFER_LEN]; + char posFormatBuf4[POS_FORMAT_BUFFER_LEN]; + char posFormatBuf5[POS_FORMAT_BUFFER_LEN]; + char posFormatBuf6[POS_FORMAT_BUFFER_LEN]; + + log( aafi->log, " %s Clip (%u): Start: %s%s%s Len: %s%s%s End: %s%s%s SourceOffset: %s%s%s Channels: %s%i%s", + ( trackLineItemCounter < totalTrackLineItems ) ? TREE_ENTRY : TREE_LAST_ENTRY, + aafi_get_clipIndex(audioClip), + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( (audioClip->pos + sessionStart), audioClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf1 ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( (audioClip->len), audioClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf2 ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( (audioClip->pos + sessionStart + audioClip->len), audioClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf3 ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( audioClip->essence_offset, audioClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf4 ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + audioClip->channels, + ANSI_COLOR_RESET(aafi->log) ); + + if ( audioClip->mute ) { + log( aafi->log, " Mute: %s%s%s", + ANSI_COLOR_DARKGREY(aafi->log), + "MUTE", + ANSI_COLOR_RESET(aafi->log) ); + } + + if ( audioClip->gain ) { + log( aafi->log, " Gain: %s%s%s", + ANSI_COLOR_DARKGREY(aafi->log), + gainToStr( audioClip->gain ), + ANSI_COLOR_RESET(aafi->log) ); + } + + if ( audioClip->automation ) { + log( aafi->log, " VolumeAutomation: %s%s%s", + ANSI_COLOR_DARKGREY(aafi->log), + "YES", + ANSI_COLOR_RESET(aafi->log) ); + } + + if ( fadein ) { + log( aafi->log, " FadeIn: %s%s (%s)%s", + ANSI_COLOR_DARKGREY(aafi->log), + INTERPOL_TO_STRING( fadein ), + formatPosValue( fadein->len, audioClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf5 ), + ANSI_COLOR_RESET(aafi->log) ); + } + + if ( fadeout ) { + log( aafi->log, " FadeOut: %s%s (%s)%s", + ANSI_COLOR_DARKGREY(aafi->log), + INTERPOL_TO_STRING( fadeout ), + formatPosValue( fadeout->len, audioClip->track->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf6 ), + ANSI_COLOR_RESET(aafi->log) ); + } + + if ( audioClip->subClipName ) { + log( aafi->log, " ClipName: %s\"%s\"%s", + ANSI_COLOR_DARKGREY(aafi->log), + audioClip->subClipName, + ANSI_COLOR_RESET(aafi->log) ); + } + + log( aafi->log, "\n" ); + + + int clipLineItemCounter = 1; + int totalClipLineItems = 0; + totalClipLineItems += ( show_metadata && audioClip->metadata ) ? 1 : 0; + totalClipLineItems += ( show_automation && audioClip->automation ) ? 1 : 0; + + aafiAudioEssencePointer *audioEssencePtr = NULL; + + AAFI_foreachEssencePointer( audioClip->essencePointerList, audioEssencePtr ) { + totalClipLineItems++; + } + + + AAFI_foreachEssencePointer( audioClip->essencePointerList, audioEssencePtr ) { + if ( audioEssencePtr->essenceChannel ) { + log( aafi->log, " %s %s SourceFile [ch %i]: %s\"%s\"%s\n", + ( trackLineItemCounter < totalTrackLineItems ) ? TREE_LINE : " ", + ( clipLineItemCounter < totalClipLineItems ) ? TREE_ENTRY : TREE_LAST_ENTRY, + audioEssencePtr->essenceChannel, + ANSI_COLOR_DARKGREY(aafi->log), + audioEssencePtr->essenceFile->unique_name, + ANSI_COLOR_RESET(aafi->log) ); + } + else { + log( aafi->log, " %s %s SourceFile [ch ALL]: %s\"%s\"%s\n", + ( trackLineItemCounter < totalTrackLineItems ) ? TREE_LINE : " ", + ( clipLineItemCounter < totalClipLineItems ) ? TREE_ENTRY : TREE_LAST_ENTRY, + ANSI_COLOR_DARKGREY(aafi->log), + audioEssencePtr->essenceFile->unique_name, + ANSI_COLOR_RESET(aafi->log) ); + } + clipLineItemCounter++; + } + + + if ( show_metadata && audioClip->metadata ) { + + log( aafi->log, " %s %s Metadata %s\n", + ( trackLineItemCounter < totalTrackLineItems ) ? TREE_LINE : " ", + ( clipLineItemCounter < totalClipLineItems ) ? TREE_ENTRY : TREE_LAST_ENTRY, + "\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80" ); + + char padding[16]; + snprintf( padding, sizeof(padding), " %s %s ", + ( trackLineItemCounter < totalTrackLineItems ) ? TREE_LINE : " ", + ( clipLineItemCounter < totalClipLineItems ) ? TREE_LINE : " " ); + + + size_t longestName = getLongestMetadataName( audioClip->metadata ) + 1; + + aafiMetaData *metadata = NULL; + + AAFI_foreachMetadata( audioClip->metadata, metadata ) { + log( aafi->log, "%s- Name: %s\"%s\"%s %*s Text: %s\"%s\"%s\n", + padding, + ANSI_COLOR_DARKGREY(aafi->log), + (metadata->name) ? metadata->name : "", + ANSI_COLOR_RESET(aafi->log), + + (metadata->name) ? (int)(longestName-strlen(metadata->name)) : (int)(longestName-strlen("")), " ", + + ANSI_COLOR_DARKGREY(aafi->log), + metadata->text, + ANSI_COLOR_RESET(aafi->log) ); + } + + clipLineItemCounter++; + } + + if ( show_automation && audioClip->automation ) { + + log( aafi->log, " %s %s Clip Volume Automation %s\n", + ( trackLineItemCounter < totalTrackLineItems ) ? TREE_LINE : " ", + ( clipLineItemCounter < totalClipLineItems ) ? TREE_ENTRY : TREE_LAST_ENTRY, + "\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80" ); + + char padding[16]; + snprintf( padding, sizeof(padding), " %s %s ", + ( trackLineItemCounter < totalTrackLineItems ) ? TREE_LINE : " ", + ( clipLineItemCounter < totalClipLineItems ) ? TREE_LINE : " " ); + + dumpVaryingValues( aafi, audioClip->automation, 1, padding ); + clipLineItemCounter++; + } + + log( aafi->log, " %s\n", + ( trackLineItemCounter < totalTrackLineItems ) ? TREE_LINE : " " ); + + trackLineItemCounter++; + } + } + + + if ( show_automation && audioTrack->pan != NULL && audioTrack->pan->flags & AAFI_AUDIO_GAIN_VARIABLE ) { + + log( aafi->log, " %s Track Pan Automation %s\n", + TREE_LAST_ENTRY, + "\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80" ); + + const char *padding = " "; + if ( trackLineItemCounter < totalTrackLineItems ) { + padding = TREE_PADDED_LINE; + } + + dumpVaryingValues( aafi, audioTrack->pan, 0, padding ); + trackLineItemCounter++; + } + + + if ( show_automation && audioTrack->gain != NULL && audioTrack->gain->flags & AAFI_AUDIO_GAIN_VARIABLE ) { + + log( aafi->log, " %s Track Volume Automation %s\n", + TREE_LAST_ENTRY, + "\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80" ); + + const char *padding = " "; + if ( trackLineItemCounter < totalTrackLineItems ) { + padding = TREE_PADDED_LINE; + } + + dumpVaryingValues( aafi, audioTrack->gain, 0, padding ); + trackLineItemCounter++; + } + + log( aafi->log, "\n" ); + } + + + + if ( aafi->Markers ) { + log( aafi->log, "Markers :\n" + "=========\n\n" ); + } + + uint32_t markerCount = 0; + aafiMarker *marker = NULL; + + AAFI_foreachMarker( aafi, marker ) { + + /* + * Composition Timecode does not always share the same edit rate as markers. + * Therefore, we need to do the conversion prior to any maths. + * For exemple, if TC is 30000/1001 and markers are 48000/1, then TC->start has to be converted from FPS to samples. + */ + + sessionStart = aafi_convertUnit( aafi->compositionStart, aafi->compositionStart_editRate, marker->edit_rate ); + + char posFormatBuf1[POS_FORMAT_BUFFER_LEN]; + char posFormatBuf2[POS_FORMAT_BUFFER_LEN]; + + log( aafi->log, " Marker[%i]: EditRate: %s%i/%i (%s)%s Start: %s%s%s Length: %s%s%s Color: %s#%02x%02x%02x%s Label: %s\"%s\"%s Comment: %s\"%s\"%s\n", + markerCount++, + + ANSI_COLOR_DARKGREY(aafi->log), + marker->edit_rate->numerator, + marker->edit_rate->denominator, + float2str( f2sbuf, "%02.2f", aafRationalToDouble(*marker->edit_rate) ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( (marker->start + sessionStart), marker->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf1 ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + formatPosValue( marker->length, marker->edit_rate, posFormat, tcFormat, &displaySamplerate, posFormatBuf2 ), + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + marker->RGBColor[0], + marker->RGBColor[1], + marker->RGBColor[2], + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + marker->name, + ANSI_COLOR_RESET(aafi->log), + + ANSI_COLOR_DARKGREY(aafi->log), + marker->comment, + ANSI_COLOR_RESET(aafi->log) ); + } + } + + + if ( extract_essences ) { + + int hasEmbeddedEssences = 0; + aafiAudioEssenceFile *audioEssenceFile = NULL; + + AAFI_foreachAudioEssenceFile( aafi, audioEssenceFile ) { + + if ( audioEssenceFile->is_embedded ) { + if ( aafi_extractAudioEssenceFile( aafi, audioEssenceFile, extract_format, extract_path, 0, 0, NULL, NULL ) == 0 ) { + log( aafi->log, "[%ssuccess%s] Audio essence file extracted to %s\"%s\"%s\n", ANSI_COLOR_GREEN(aafi->log), ANSI_COLOR_RESET(aafi->log), ANSI_COLOR_DARKGREY(aafi->log), audioEssenceFile->usable_file_path, ANSI_COLOR_RESET(aafi->log) ); + } else { + log( aafi->log, "[%s error %s] Audio essence file extraction failed : %s\"%s\"%s\n", ANSI_COLOR_RED(aafi->log), ANSI_COLOR_RESET(aafi->log), ANSI_COLOR_DARKGREY(aafi->log), audioEssenceFile->unique_name, ANSI_COLOR_RESET(aafi->log) ); + } + hasEmbeddedEssences = 1; + } + } + + if ( !hasEmbeddedEssences ) { + log( aafi->log, "[%s error %s] File has no embedded essence to extract.\n", ANSI_COLOR_RED(aafi->log), ANSI_COLOR_RESET(aafi->log) ); + } + } + + + if ( extract_clips ) { + + aafiAudioTrack *audioTrack = NULL; + aafiTimelineItem *audioItem = NULL; + aafiAudioClip *audioClip = NULL; + + AAFI_foreachAudioTrack( aafi, audioTrack ) { + + AAFI_foreachTrackItem( audioTrack, audioItem ) { + + if ( audioItem->type != AAFI_AUDIO_CLIP ) { + continue; + } + + audioClip = audioItem->data; + + aafi_extractAudioClip( aafi, audioClip, extract_format, extract_path ); + } + } + } + + goto end; + +err: + rc = -1; + +end: + + free( aafPath ); + + free( get_node_str ); + + aafi_release( &aafi ); + + if ( logfp != stdout ) { + fclose( logfp ); + } + + return rc; +} diff --git a/tools/common.c b/tools/common.c deleted file mode 100644 index 2dfb8b5..0000000 --- a/tools/common.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2017-2023 Adrien Gesta-Fline - * - * This file is part of libAAF. - * - * 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 "common.h" - -#ifdef _WIN32 - #include - #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING - #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 - #endif -#endif - - - -void enable_windows_VT100_output( void ) { -#ifdef _WIN32 - /* enables ANSI colors and unicode chars */ - HANDLE hOut = GetStdHandle( STD_OUTPUT_HANDLE ); - DWORD dwMode = 0; - GetConsoleMode( hOut, &dwMode ); - SetConsoleMode( hOut, (dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING) ); -#endif -} diff --git a/tools/thirdparty/libTC.c b/tools/thirdparty/libTC.c index c2cc2fc..ecab3ce 100644 --- a/tools/thirdparty/libTC.c +++ b/tools/thirdparty/libTC.c @@ -1,208 +1,305 @@ +/* + * Copyright (C) 2017-2024 Adrien Gesta-Fline + * + * This file is part of libAAF. + * + * 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 // abs() #include // round() +#include #include "libTC.h" /* - * SMPTE ST12-1 p9 : - * Sufficient precision is necessary in calculations to assure that rounding or - * truncation operations will not create errors in the end result. + * SMPTE ST12-1 p9 : + * Sufficient precision is necessary in calculations to assure that rounding or + * truncation operations will not create errors in the end result. */ static rational_t TC_FPS[] = { - {0x00000000, 0x00000001}, // UNKNOWN 0/1 - {0x00005dc0, 0x000003e9}, // TC_23_976 24000/1001 - {0x00000018, 0x00000001}, // TC_24 24/1 - {0x00000019, 0x00000001}, // TC_25 25/1 - {0x00007530, 0x000003e9}, // TC_29_97_NDF 30000/1001 - {0x00007530, 0x000003e9}, // TC_29_97_DF 30000/1001 - {0x0000001e, 0x00000001}, // TC_30 30/1 - {0x0000bb80, 0x000003e9}, // TC_47_95 48000/1001 - {0x00000030, 0x00000001}, // TC_48 48/1 - {0x00000032, 0x00000001}, // TC_50 50/1 - {0x0000ea60, 0x000003e9}, // TC_59_94_NDF 60000/1001 - {0x0000ea60, 0x000003e9}, // TC_59_94_DF 60000/1001 - {0x0000003c, 0x00000001}, // TC_60 60/1 - {0x00000048, 0x00000001}, // TC_72 72/1 - {0x00000060, 0x00000001}, // TC_96 96/1 - {0x00000064, 0x00000001}, // TC_100 100/1 - {0x00000078, 0x00000001} // TC_120 120/1 + {0x00000000, 0x00000001}, /* UNKNOWN 0/1 */ + {0x00005dc0, 0x000003e9}, /* TC_23_976 24000/1001 */ + {0x00000018, 0x00000001}, /* TC_24 24/1 */ + {0x00000019, 0x00000001}, /* TC_25 25/1 */ + {0x00007530, 0x000003e9}, /* TC_29_97_NDF 30000/1001 */ + {0x00007530, 0x000003e9}, /* TC_29_97_DF 30000/1001 */ + {0x0000001e, 0x00000001}, /* TC_30_NDF 30/1 */ + {0x0000001e, 0x00000001}, /* TC_30_DF 30/1 */ + {0x0000bb80, 0x000003e9}, /* TC_47_95 48000/1001 */ + {0x00000030, 0x00000001}, /* TC_48 48/1 */ + {0x00000032, 0x00000001}, /* TC_50 50/1 */ + {0x0000ea60, 0x000003e9}, /* TC_59_94_NDF 60000/1001 */ + {0x0000ea60, 0x000003e9}, /* TC_59_94_DF 60000/1001 */ + {0x0000003c, 0x00000001}, /* TC_60_NDF 60/1 */ + {0x0000003c, 0x00000001}, /* TC_60_DF 60/1 */ + {0x00000048, 0x00000001}, /* TC_72 72/1 */ + {0x00000060, 0x00000001}, /* TC_96 96/1 */ + {0x00000064, 0x00000001}, /* TC_100 100/1 */ + {0x00002ed4, 0x00000064}, /* TC_119_88_NDF 11988/100 */ + {0x00002ed4, 0x00000064}, /* TC_119_88_DF 11988/100 */ + {0x00000078, 0x00000001}, /* TC_120_NDF 120/1 */ + {0x00000078, 0x00000001} /* TC_120_DF 120/1 */ }; -/* -static char *TC_FORMAT_STR[] = { +const char *TC_FORMAT_STR[] = { "unknown", "TC_23_976", "TC_24", "TC_25", "TC_29_97_NDF", "TC_29_97_DF", - "TC_30", + "TC_30_NDF", + "TC_30_DF", "TC_47_95", "TC_48", "TC_50", "TC_59_94_NDF", "TC_59_94_DF", - "TC_60", + "TC_60_NDF", + "TC_60_DF", "TC_72", "TC_96", "TC_100", - "TC_120" + "TC_119_88_NDF", + "TC_119_88_DF", + "TC_120_NDF", + "TC_120_DF" }; -*/ +#define TC_RATIONAL_TO_FLOAT( r ) \ + (( r.denominator == 0 ) ? 0 : ((float)r.numerator/(float)r.denominator)) -static void unitValueToFrames( struct timecode *tc ) -{ - float fps = aafRationalToFloat( TC_FPS[tc->format] ); - float unitRate = aafRationalToFloat( tc->unitRate ); - tc->frameNumber = (uint32_t)( tc->unitValue / ( unitRate / fps ) ); -} +static int is_format_drop_frame( enum TC_FORMAT tcfmt ); +static void unitValueToFrames( struct timecode *tc ); +static void hmsfToString( struct timecode *tc ); +static void stringToHmsf( struct timecode *tc ); +static void hmsfToFrames( struct timecode *tc ); +static void framesToHmsf( struct timecode *tc, enum TC_ROLLOVER_OPT rollover ); -static void hmsfToString( struct timecode *tc ) + + +enum TC_FORMAT tc_get_format_by_fps( float fps, uint8_t isDrop ) { - char string[16]; + uint32_t ifps = (uint32_t)( fps * 100 ); - snprintf( string, 16, "%02u%c%02u%c%02u%c%02u", - (tc->hours <= 9999) ? tc->hours : 0, TC_SEP, - (tc->minutes <= 99) ? tc->minutes : 0, TC_SEP, - (tc->seconds <= 99) ? tc->seconds : 0, (tc->format == TC_29_97_DF || tc->format == TC_59_94_DF) ? TC_SEP_DROP : TC_SEP, - (tc->frames <= 999) ? tc->frames : 0 ); + // printf("%i\n", ifps ); - if ( tc->frameNumber < 0 ) { - tc->string[0] = '-'; - strcpy( tc->string+1, string ); - } - else { - strcpy( tc->string, string ); + uint16_t tc_format = 0; + + for ( tc_format = 0; tc_format < TC_FORMAT_LEN; tc_format++ ) { + + if ( ifps == (uint32_t)(TC_RATIONAL_TO_FLOAT( TC_FPS[tc_format] ) * 100) ) { + + // printf("tc_format: %i (%i) == %i\n", ifps, isDrop, (uint32_t)(TC_RATIONAL_TO_FLOAT( TC_FPS[tc_format] ) * 100) ); + + if ( ( tc_format == TC_29_97_NDF || + tc_format == TC_30_NDF || + tc_format == TC_59_94_NDF || + tc_format == TC_60_NDF || + tc_format == TC_119_88_NDF || + tc_format == TC_120_NDF ) && + isDrop == 1 ) + { + return ++tc_format; + } + + return tc_format; + } } + + return TC_FORMAT_UNK; } -static void StringToHmsf( struct timecode *tc ) +void tc_set_by_unitValue( struct timecode *tc, int64_t unitValue, rational_t *unitRate, enum TC_FORMAT format, enum TC_ROLLOVER_OPT rollover ) { - sscanf( tc->string, "%hu%*c%hu%*c%hu%*c%hu", - &tc->hours, - &tc->minutes, - &tc->seconds, - &tc->frames ); + memset( tc, 0x00, sizeof(struct timecode) ); + + if ( unitRate == NULL ) { + return; + } + + tc->format = format; + tc->unitValue = unitValue; + tc->unitRate = *unitRate; + + unitValueToFrames( tc ); + + framesToHmsf( tc, rollover ); + + hmsfToString( tc ); } -static void hmsfToFrames( struct timecode *tc ) +void tc_set_by_frames( struct timecode *tc, int32_t frameNumber, enum TC_FORMAT format, enum TC_ROLLOVER_OPT rollover ) { - float fps = round(aafRationalToFloat( TC_FPS[tc->format] )); - - uint32_t dropFrames = 0; + memset( tc, 0x00, sizeof(struct timecode) ); - if ( tc->format == TC_29_97_DF || - tc->format == TC_59_94_DF ) - { - dropFrames = (tc->hours * (2 * 9 * 6)) + \ - ((tc->minutes / 10) * (2 * 9)) + \ - (((tc->minutes % 10)) * 2); - // - ((tc->minutes % 10) ? 2 : 0 ); // we don't take out the first two frame numbers (00 and 01) of the current 10min block because we start the counting at 0.. - } + tc->format = format; + tc->frameNumber = frameNumber; + framesToHmsf( tc, rollover ); - tc->frameNumber = ( tc->hours * 3600 * fps ) + \ - ( tc->minutes * 60 * fps ) + \ - ( tc->seconds * fps ) + \ - ( tc->frames ) - \ - dropFrames; + hmsfToString( tc ); } -static void framesToHmsf( struct timecode *tc ) +// void rollover( struct timecode *tc ) { +// +// float fps = round( TC_RATIONAL_TO_FLOAT( TC_FPS[tc->format] ) ); +// +// if ( is_format_drop_frame(tc->format) ) { +// +// /* +// * SMPTE ST 12-1 p10 : +// * To minimize the NTSC time deviation from real time, the first two +// * frame numbers (00 and 01) shall be omitted from the count at the +// * start of each minute except minutes 00, 10, 20, 30, 40, and 50. +// */ +// +// if ( rollover == TC_ROLLOVER ) { +// /* Rollover if frameNumber > 23:59:59:XX */ +// uint32_t frameNumber24h = (((((fps*60))*10) - (2*9)) * 6 * 24); +// frameNumber = frameNumber % frameNumber24h; +// } +// +// +// int32_t framesPerMinute = (fps * 60) - 2; +// int32_t framesPer10Minutes = (framesPerMinute * 10) + 2; +// +// int32_t chunksOf10Minutes = frameNumber / framesPer10Minutes; +// int32_t chunksOf1Minute = ((int32_t)(frameNumber % framesPer10Minutes) - 2) / framesPerMinute; /* minus 2 corresponds to the first two frame numbers (00 and 01) */ +// +// int32_t tenMinuteDrops = 2 * 9 * chunksOf10Minutes; +// int32_t oneMinuteDrops = ( chunksOf1Minute < 0 ) ? 0 : (2 * chunksOf1Minute); +// +// +// uint32_t dropFrames = tenMinuteDrops + oneMinuteDrops; +// +// +// if ( tc->format == TC_59_94_DF || +// tc->format == TC_60_DF ) +// { +// dropFrames *= 2; +// } +// else if ( tc->format == TC_119_88_DF || +// tc->format == TC_120_DF ) +// { +// dropFrames *= 4; +// } +// +// frameNumber += dropFrames; +// } +// else if ( rollover == TC_ROLLOVER ) { +// /* Rollover if frameNumber > 23:59:59:XX */ +// uint32_t frameNumber24h = (((fps*60)*10) * 6 * 24); +// frameNumber = (frameNumber24h) ? frameNumber % frameNumber24h : 0; +// } +// } + + + +void tc_set_by_hmsf( struct timecode *tc, int hours, int minutes, int seconds, int frames, enum TC_FORMAT format, enum TC_ROLLOVER_OPT rollover ) { - int32_t frameNumber = abs( tc->frameNumber ); + memset( tc, 0x00, sizeof(struct timecode) ); - float fps = round( aafRationalToFloat( TC_FPS[tc->format] ) ); + tc->format = format; + tc->hours = hours; + tc->minutes = minutes; + tc->seconds = seconds; + tc->frames = frames; + hmsfToFrames( tc ); - if ( tc->format == TC_29_97_DF || - tc->format == TC_59_94_DF ) - { - /* - * SMPTE ST 12-1 p10 : - * To minimize the NTSC time deviation from real time, the first two - * frame numbers (00 and 01) shall be omitted from the count at the - * start of each minute except minutes 00, 10, 20, 30, 40, and 50. - */ + if ( rollover ) { + framesToHmsf( tc, rollover ); + } + hmsfToString( tc ); - /* - * Rollover if frameNumber > 23:59:59:29 - */ + // if ( rollover ) { + // rollover( tc ); + // } +} - if ( tc->noRollover == 0 ) { - uint32_t frameNumber24h = (((((fps*60))*10) - (2*9)) * 6 * 24); // 2589408 frames @ 29.97fps - frameNumber = frameNumber % frameNumber24h; - } - int32_t framesPerMinute = (fps * 60) - 2; - int32_t framesPer10Minutes = (framesPerMinute * 10) + 2; +void tc_set_by_string( struct timecode *tc, const char *str, enum TC_FORMAT format, enum TC_ROLLOVER_OPT rollover ) +{ + memset( tc, 0x00, sizeof(struct timecode) ); - int32_t chunksOf10Minutes = frameNumber / framesPer10Minutes; - int32_t chunksOf1Minute = ((int32_t)(frameNumber % framesPer10Minutes) - 2) / framesPerMinute; // minus 2 correspond to the first two frame numbers (00 and 01) + tc->format = format; + strncpy( tc->string, str, sizeof(((struct timecode){0}).string)-1 ); - int32_t tenMinuteDrops = 2 * 9 * chunksOf10Minutes; - int32_t oneMinuteDrops = ( chunksOf1Minute < 0 ) ? 0 : (2 * chunksOf1Minute); + stringToHmsf( tc ); + hmsfToFrames( tc ); - uint32_t dropFrames = tenMinuteDrops + oneMinuteDrops; + if ( rollover ) { + framesToHmsf( tc, rollover ); + hmsfToString( tc ); + } + // if ( rollover ) { + // rollover( tc ); + // } +} - if ( tc->format == TC_59_94_DF ) { - dropFrames *= 2; - } - // printf(" frameNumber : %u\n", tc->frameNumber ); - // printf(" frame per second : %02.2f\n", fps ); - // printf(" framesPerMinute : %u\n", framesPerMinute ); - // printf(" framesPer10Minutes : %u\n", framesPer10Minutes ); - // printf(" chunksOf1Minute : %i\n", chunksOf1Minute ); - // printf(" chunksOf10Minutes : %u\n", chunksOf10Minutes ); - // printf(" oneMinuteDrops : %u\n", oneMinuteDrops ); - // printf(" tenMinuteDrops : %u\n", tenMinuteDrops ); - // printf(" dropFrames : %u\n", dropFrames ); - - frameNumber += dropFrames; - } - else - if ( tc->noRollover == 0 ) { - /* - * Rollover if frameNumber > 23:59:59:29 - */ - uint32_t frameNumber24h = (((fps*60)*10) * 6 * 24); - frameNumber = frameNumber % frameNumber24h; - } +void tc_set_format( struct timecode *tc, enum TC_FORMAT format, enum TC_ROLLOVER_OPT rollover ) +{ + tc->format = format; - tc->frames = frameNumber % (uint32_t)fps; - tc->seconds = (frameNumber / (uint32_t)fps) % 60; - tc->minutes = ((frameNumber / (uint32_t)fps) / 60) % 60; - tc->hours = ((frameNumber / (uint32_t)fps) / 60) / 60; + framesToHmsf( tc, rollover ); + hmsfToString( tc ); } -int tc_add( struct timecode *tc_a, struct timecode *tc_b ) +// void tc_convert( struct timecode *tc, enum TC_FORMAT format, enum TC_ROLLOVER_OPT rollover ) +// { +// tc->format = format; +// +// if ( tc->frames > round(TC_RATIONAL_TO_FLOAT(TC_FPS[format])) ) { +// tc->frames = round(TC_RATIONAL_TO_FLOAT(TC_FPS[format])) - 1; +// } +// +// hmsfToFrames( tc ); +// framesToHmsf( tc, rollover ); +// hmsfToString( tc ); +// } + + + +int tc_add( struct timecode *tc_a, struct timecode *tc_b, enum TC_ROLLOVER_OPT rollover ) { if ( tc_a->format != tc_b->format ) { return -1; @@ -210,7 +307,7 @@ int tc_add( struct timecode *tc_a, struct timecode *tc_b ) tc_a->frameNumber += tc_b->frameNumber; - framesToHmsf( tc_a ); + framesToHmsf( tc_a, rollover ); hmsfToString( tc_a ); @@ -219,7 +316,7 @@ int tc_add( struct timecode *tc_a, struct timecode *tc_b ) -int tc_sub( struct timecode *tc_a, struct timecode *tc_b ) +int tc_sub( struct timecode *tc_a, struct timecode *tc_b, enum TC_ROLLOVER_OPT rollover ) { if ( tc_a->format != tc_b->format ) { return -1; @@ -227,7 +324,7 @@ int tc_sub( struct timecode *tc_a, struct timecode *tc_b ) tc_a->frameNumber -= tc_b->frameNumber; - framesToHmsf( tc_a ); + framesToHmsf( tc_a, rollover ); hmsfToString( tc_a ); @@ -236,135 +333,178 @@ int tc_sub( struct timecode *tc_a, struct timecode *tc_b ) -void tc_convert( struct timecode *tc, enum TC_FORMAT format ) +static int is_format_drop_frame( enum TC_FORMAT tcfmt ) { - tc->format = format; - - framesToHmsf( tc ); - hmsfToString( tc ); + return ( tcfmt == TC_29_97_DF || + tcfmt == TC_30_DF || + tcfmt == TC_59_94_DF || + tcfmt == TC_60_DF || + tcfmt == TC_119_88_DF || + tcfmt == TC_120_DF ); } -void tc_convert_frames( struct timecode *tc, enum TC_FORMAT format ) +static void unitValueToFrames( struct timecode *tc ) { - tc->format = format; + float fps = TC_RATIONAL_TO_FLOAT( TC_FPS[tc->format] ); + float unitRate = TC_RATIONAL_TO_FLOAT( tc->unitRate ); + + if ( fps == unitRate ) { - if ( tc->frames > round(aafRationalToFloat(TC_FPS[format])) ) { - tc->frames = round(aafRationalToFloat(TC_FPS[format])) - 1; + assert( unitRate > INT_MIN && unitRate < INT_MAX ); + + tc->frameNumber = (int32_t)tc->unitValue; + + } else { + tc->frameNumber = (int32_t)( (float)tc->unitValue / ( (float)unitRate / (float)fps ) ); } - hmsfToFrames( tc ); - framesToHmsf( tc ); - hmsfToString( tc ); + // printf( "%lu (%i/%i) -> %u (%i/%i)\n", + // tc->unitValue, + // tc->unitRate.numerator, + // tc->unitRate.denominator, + // tc->frameNumber, + // TC_FPS[tc->format].numerator, + // TC_FPS[tc->format].denominator ); } -enum TC_FORMAT tc_fps2format( float fps, uint8_t isDrop ) +static void hmsfToString( struct timecode *tc ) { - /* TODO is function ok ? */ - - uint32_t ifps = (uint32_t)( fps * 100 ); + snprintf( tc->string, 16, "%s%02u%c%02u%c%02u%c%02u", + (tc->frameNumber < 0) ? "-" : "", + (tc->hours <= 9999) ? tc->hours : 0, TC_SEP_CHAR, + (tc->minutes <= 99) ? tc->minutes : 0, TC_SEP_CHAR, + (tc->seconds <= 99) ? tc->seconds : 0, (is_format_drop_frame( tc->format )) ? TC_SEP_DROP_CHAR : TC_SEP_CHAR, + (tc->frames <= 999) ? tc->frames : 0 ); +} - // printf("%i\n", ifps ); - uint16_t tc_format = 0; - for ( tc_format = 0; tc_format < TC_FORMAT_LEN; tc_format++ ) { +static void stringToHmsf( struct timecode *tc ) +{ + // sscanf( tc->string, "%hi%*c%hi%*c%hi%*c%hi", + sscanf( tc->string, "%i%*c%i%*c%i%*c%i", + &tc->hours, + &tc->minutes, + &tc->seconds, + &tc->frames ); +} - if ( ifps == (uint32_t)(aafRationalToFloat( TC_FPS[tc_format] ) * 100) ) { - if ( ( tc_format == TC_29_97_NDF || - tc_format == TC_59_94_NDF ) && - isDrop == 1 ) - { - return tc_format++; - } - return tc_format; - } - } - - return TC_FORMAT_UNK; -} +static void hmsfToFrames( struct timecode *tc ) +{ + double fps = round(TC_RATIONAL_TO_FLOAT( TC_FPS[tc->format] )); + uint32_t dropFrames = 0; + if ( is_format_drop_frame(tc->format) ) { + int dropFramesInt = (tc->hours * (2 * 9 * 6)) + \ + ((tc->minutes / 10) * (2 * 9)) + \ + (((tc->minutes % 10)) * 2); -void tc_set_by_string( struct timecode *tc, const char *str, enum TC_FORMAT format ) -{ - tc->format = format; + assert( dropFramesInt >= 0 ); - tc->noRollover = 0; + dropFrames = (uint32_t)dropFramesInt; + } - strncpy( tc->string, str, 12 ); + if ( tc->format == TC_59_94_DF || + tc->format == TC_60_DF ) + { + dropFrames *= 2; + } + else if ( tc->format == TC_119_88_DF || + tc->format == TC_120_DF ) + { + dropFrames *= 4; + } + double frameNumber = (tc->hours * 3600 * fps) + \ + (tc->minutes * 60 * fps) + \ + (tc->seconds * fps ) + \ + (tc->frames ) - \ + dropFrames; - StringToHmsf( tc ); + assert( frameNumber > INT_MIN && frameNumber < INT_MAX ); - hmsfToFrames( tc ); + tc->frameNumber = (int32_t)frameNumber; } -void tc_set_by_frames( struct timecode *tc, uint32_t frameNumber, enum TC_FORMAT format ) +static void framesToHmsf( struct timecode *tc, enum TC_ROLLOVER_OPT rollover ) { - /* TODO test or set to zero */ + int32_t frameNumber = abs( tc->frameNumber ); - tc->unitValue = frameNumber; - memcpy( &tc->unitRate, &TC_FPS[format], sizeof(rational_t) ); + double fps = round( TC_RATIONAL_TO_FLOAT( TC_FPS[tc->format] ) ); - tc->frameNumber = frameNumber; - tc->format = format; - tc->noRollover = 0; + if ( is_format_drop_frame(tc->format) ) { + /* + * SMPTE ST 12-1 p10 : + * To minimize the NTSC time deviation from real time, the first two + * frame numbers (00 and 01) shall be omitted from the count at the + * start of each minute except minutes 00, 10, 20, 30, 40, and 50. + */ - framesToHmsf( tc ); - - hmsfToString( tc ); -} + if ( rollover == TC_ROLLOVER ) { + /* Rollover if frameNumber > 23:59:59:XX */ + double frameNumber24hdouble = (((((fps*60))*10) - (2*9)) * 6 * 24/*hours*/); + assert( frameNumber24hdouble > 0 && frameNumber24hdouble < INT_MAX ); + int32_t frameNumber24h = (int32_t)frameNumber24hdouble; -void tc_set_by_hmsf( struct timecode *tc, uint16_t hours, uint16_t minutes, uint16_t seconds, uint16_t frames, enum TC_FORMAT format ) -{ - tc->hours = hours; - tc->minutes = minutes; - tc->seconds = seconds; - tc->frames = frames; + frameNumber = frameNumber % frameNumber24h; + } - tc->format = format; + double framesPerMinuteDouble = (fps * 60) - 2; - tc->noRollover = 0; + assert( framesPerMinuteDouble > 0 && framesPerMinuteDouble < INT_MAX ); + int32_t framesPerMinute = (int32_t)framesPerMinuteDouble; - hmsfToFrames( tc ); + int32_t framesPer10Minutes = (framesPerMinute * 10) + 2; - hmsfToString( tc ); -} + int32_t chunksOf10Minutes = frameNumber / framesPer10Minutes; + int32_t chunksOf1Minute = ((int32_t)(frameNumber % framesPer10Minutes) - 2) / framesPerMinute; /* minus 2 corresponds to the first two frame numbers (00 and 01) */ + int32_t tenMinuteDrops = 2 * 9 * chunksOf10Minutes; + int32_t oneMinuteDrops = (chunksOf1Minute < 0) ? 0 : (2 * chunksOf1Minute); + int32_t droppedFrames = abs( tenMinuteDrops + oneMinuteDrops ); -void tc_set_by_unitValue( struct timecode *tc, uint64_t unitValue, rational_t *unitRate, enum TC_FORMAT format ) -{ - memset( tc, 0x00, sizeof(struct timecode) ); + if ( tc->format == TC_59_94_DF || + tc->format == TC_60_DF ) + { + droppedFrames *= 2; + } + else if ( tc->format == TC_119_88_DF || + tc->format == TC_120_DF ) + { + droppedFrames *= 4; + } - if ( unitRate == NULL ) { - return; + frameNumber += droppedFrames; } + else if ( rollover == TC_ROLLOVER ) { + /* Rollover if frameNumber > 23:59:59:XX */ + double frameNumber24hdouble = (((fps*60)*10) * 6 * 24); - tc->unitValue = unitValue; - tc->unitRate = *unitRate; - - tc->format = format; - - tc->noRollover = 0; + assert( frameNumber24hdouble > 0 && frameNumber24hdouble < INT_MAX ); + int32_t frameNumber24h = (int32_t)frameNumber24hdouble; - unitValueToFrames( tc ); + frameNumber = (frameNumber24h) ? frameNumber % frameNumber24h : 0; + } - framesToHmsf( tc ); - hmsfToString( tc ); + tc->frames = frameNumber % (int32_t)fps; + tc->seconds = (frameNumber / (int32_t)fps) % 60; + tc->minutes = ((frameNumber / (int32_t)fps) / 60) % 60; + tc->hours = ((frameNumber / (int32_t)fps) / 60) / 60; } diff --git a/tools/thirdparty/libTC.h b/tools/thirdparty/libTC.h index 776f1af..e340d18 100644 --- a/tools/thirdparty/libTC.h +++ b/tools/thirdparty/libTC.h @@ -1,54 +1,68 @@ -#ifndef __libTC_h__ -#define __libTC_h__ - /* - * This file is part of LibAAF. + * Copyright (C) 2017-2024 Adrien Gesta-Fline * - * Copyright (c) 2017 Adrien Gesta-Fline + * This file is part of libAAF. * - * LibAAF is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. + * 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. * - * LibAAF is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. + * 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 Affero General Public License - * along with LibAAF. If not, see . + * 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 __libTC_h__ +#define __libTC_h__ + + #include #include +#if defined(__linux__) + #include + #include +#elif defined(__APPLE__) + #include +#elif defined(_WIN32) + #include // MAX_PATH + #include +#endif + -#define TC_SEP ':' -#define TC_SEP_DROP ';' +#define TC_SEP_CHAR ':' +#define TC_SEP_DROP_CHAR ';' +#define TC_SEP_STR ":" +#define TC_SEP_DROP_STR ";" /* - * SMPTE ST12-1 p6 : - * This Standard specifies a time and control code for use in television and - * accompanying audio systems operating at nominal rates of 60, 59.94, 50, - * 48, 47.95, 30, 29.97, 25, 24, and 23.98 frames per second. + * SMPTE ST12-1 p6 : + * This Standard specifies a time and control code for use in television and + * accompanying audio systems operating at nominal rates of 60, 59.94, 50, + * 48, 47.95, 30, 29.97, 25, 24, and 23.98 frames per second. * - * SMPTE ST428-11:2013 p3 : - * This first part defines the additional frame rates individually at 25, 30, - * 50, 60, 96, 100 and 120 frames per second. + * SMPTE ST428-11:2013 p3 : + * This first part defines the additional frame rates individually at 25, 30, + * 50, 60, 96, 100 and 120 frames per second. * - * NOTE about 30 DF and 60 DF (from "Pro Tools for Video, Film and Multimedia" p45) : - * Many manufacturers, including Digidesign, label one time code format as 30 fps - * drop-frame. This is not a real format. The term is commonly misused as a name - * for 29.97 drop-frame. If you think about it, 30 fps does not need to drop frame - * numbers in order to be in sync with the real-time clock. - * There would be no normal use for 30 drop-frame time code. In Pro Tools, the time - * code options include both 29.97 drop-frame and 30 drop-frame. The 30 drop-frame - * is a true 30fps with skipped frame numbers. In relation to the real-time clock, - * this format runs faster, and after one hour of real-time, reads: 01:00:03:18. - * This format is very misleading and should only be used when correcting errors - * in existing time code. Beware, and double check your time code format! + * NOTE about 30 DF and 60 DF (from "Pro Tools for Video, Film and Multimedia" p45) : + * Many manufacturers, including Digidesign, label one time code format as 30 fps + * drop-frame. This is not a real format. The term is commonly misused as a name + * for 29.97 drop-frame. If you think about it, 30 fps does not need to drop frame + * numbers in order to be in sync with the real-time clock. + * There would be no normal use for 30 drop-frame time code. In Pro Tools, the time + * code options include both 29.97 drop-frame and 30 drop-frame. The 30 drop-frame + * is a true 30fps with skipped frame numbers. In relation to the real-time clock, + * this format runs faster, and after one hour of real-time, reads: 01:00:03:18. + * This format is very misleading and should only be used when correcting errors + * in existing time code. Beware, and double check your time code format! * */ @@ -61,143 +75,69 @@ enum TC_FORMAT { TC_25, TC_29_97_NDF, TC_29_97_DF, - TC_30, + TC_30_NDF, + TC_30_DF, TC_47_95, TC_48, TC_50, TC_59_94_NDF, TC_59_94_DF, - TC_60, + TC_60_NDF, + TC_60_DF, TC_72, TC_96, TC_100, - TC_120, + TC_119_88_NDF, + TC_119_88_DF, + TC_120_NDF, + TC_120_DF, TC_FORMAT_LEN }; +extern const char *TC_FORMAT_STR[]; +enum TC_ROLLOVER_OPT { + TC_ROLLOVER = 0, + TC_NO_ROLLOVER +}; -// typedef uint64_t rational_t; -typedef struct rational_t -{ +typedef struct rational_t { int32_t numerator; int32_t denominator; - -} /*__attribute__((packed))*/ rational_t; - -// static rational_t TC_FPS[] = { -// 0x0000000000000001, // UNKNOWN 0/1 -// 0x00005dc0000003e9, // TC_23_976 24000/1001 -// 0x0000001800000001, // TC_24 24/1 -// 0x0000001900000001, // TC_25 25/1 -// 0x00007530000003e9, // TC_29_97_NDF 30000/1001 -// 0x00007530000003e9, // TC_29_97_DF 30000/1001 -// 0x0000001e00000001, // TC_30 30/1 -// 0x0000001e00000001, // TC_30_DF 30/1 -// 0x0000003200000001, // TC_50 50/1 -// 0x0000ea60000003e9, // TC_59_94_NDF 60000/1001 -// 0x0000ea60000003e9, // TC_59_94_DF 60000/1001 -// 0x0000003c00000001, // TC_60 60/1 -// 0x0000003c00000001, // TC_60_DF 60/1 -// 0x0000006000000001, // TC_96 96/1 -// 0x0000006400000001, // TC_100 100/1 -// 0x0000007800000001 // TC_120 120/1 -// }; - -// static rational_t TC_FPS[] = { -// {0x00000000, 0x00000001}, // UNKNOWN 0/1 -// {0x00005dc0, 0x000003e9}, // TC_23_976 24000/1001 -// {0x00000018, 0x00000001}, // TC_24 24/1 -// {0x00000019, 0x00000001}, // TC_25 25/1 -// {0x00007530, 0x000003e9}, // TC_29_97_NDF 30000/1001 -// {0x00007530, 0x000003e9}, // TC_29_97_DF 30000/1001 -// {0x0000001e, 0x00000001}, // TC_30 30/1 -// {0x0000001e, 0x00000001}, // TC_30_DF 30/1 -// {0x00000032, 0x00000001}, // TC_50 50/1 -// {0x0000ea60, 0x000003e9}, // TC_59_94_NDF 60000/1001 -// {0x0000ea60, 0x000003e9}, // TC_59_94_DF 60000/1001 -// {0x0000003c, 0x00000001}, // TC_60 60/1 -// {0x0000003c, 0x00000001}, // TC_60_DF 60/1 -// {0x00000060, 0x00000001}, // TC_96 96/1 -// {0x00000064, 0x00000001}, // TC_100 100/1 -// {0x00000078, 0x00000001} // TC_120 120/1 -// }; - - -#define inttorational( n, d ) \ - {n, d} - // ( ((uint64_t)n << 32) | (d & 0xffffffff) ) -/* -#define aafRationalToFloat( n ) \ - (float)(( (n & 0xffffffff) == 0 ) ? 0 : ( (float)(n >> 32) / (n & 0xffffffff) ) ) -*/ - -#ifndef aafRationalToFloat -#define aafRationalToFloat( r ) \ - (( r.denominator == 0 ) ? 0 : ((float)r.numerator/r.denominator)) -#endif - -struct timecode -{ - uint64_t unitValue; // some value of unknown unit (eg. samples) - - rational_t unitRate; // value units per second (eg. 48000) - +} rational_t; - int32_t frameNumber; - - - uint16_t hours; - - uint16_t minutes; - - uint16_t seconds; - - uint16_t frames; - +struct timecode { enum TC_FORMAT format; - uint8_t noRollover; // disable rollover if TC is bigger than day limit - - // rational_t framePerSecond; - // - // uint8_t isDropFrame; + int64_t unitValue; // some value of unknown unit (eg. samples) + rational_t unitRate; // value units per second (eg. 48000/1) - /** - * Holds the timecode as a null terminated string. - */ + int32_t frameNumber; - char string[32]; + int32_t hours; + int32_t minutes; + int32_t seconds; + int32_t frames; + char string[32]; }; -int tc_add( struct timecode *tc_a, struct timecode *tc_b ); - -int tc_sub( struct timecode *tc_a, struct timecode *tc_b ); - - -void tc_convert( struct timecode *tc, enum TC_FORMAT format ); - -void tc_convert_frames( struct timecode *tc, enum TC_FORMAT format ); - - -enum TC_FORMAT tc_fps2format( float fps, uint8_t isDrop ); - - -void tc_set_by_string( struct timecode *tc, const char *str, enum TC_FORMAT format ); - -void tc_set_by_frames( struct timecode *tc, uint32_t frameNumber, enum TC_FORMAT format ); - -void tc_set_by_hmsf( struct timecode *tc, uint16_t hours, uint16_t minutes, uint16_t seconds, uint16_t frames, enum TC_FORMAT format ); +enum TC_FORMAT tc_get_format_by_fps( float fps, uint8_t isDrop ); -void tc_set_by_unitValue( struct timecode *tc, uint64_t unitValue, rational_t *unitRate, enum TC_FORMAT format ); +void tc_set_by_unitValue( struct timecode *tc, int64_t unitValue, rational_t *unitRate, enum TC_FORMAT format, enum TC_ROLLOVER_OPT rollover ); +void tc_set_by_frames( struct timecode *tc, int32_t frameNumber, enum TC_FORMAT format, enum TC_ROLLOVER_OPT rollover ); +void tc_set_by_hmsf( struct timecode *tc, int hours, int minutes, int seconds, int frames, enum TC_FORMAT format, enum TC_ROLLOVER_OPT rollover ); +void tc_set_by_string( struct timecode *tc, const char *str, enum TC_FORMAT format, enum TC_ROLLOVER_OPT rollover ); +void tc_set_format( struct timecode *tc, enum TC_FORMAT format, enum TC_ROLLOVER_OPT rollover ); +void tc_convert( struct timecode *tc, enum TC_FORMAT format, enum TC_ROLLOVER_OPT rollover ); -// int oldTCbyFrames( struct timecode *tc, uint32_t frameNumber, rational_t framePerSecond, uint8_t isDropFrame ); +int tc_add( struct timecode *tc_a, struct timecode *tc_b, enum TC_ROLLOVER_OPT rollover ); +int tc_sub( struct timecode *tc_a, struct timecode *tc_b, enum TC_ROLLOVER_OPT rollover ); /* diff --git a/tools/win/getopt.h b/tools/win/getopt.h index 24e6661..af99c09 100644 --- a/tools/win/getopt.h +++ b/tools/win/getopt.h @@ -58,7 +58,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#pragma warning(disable:4996); +// #pragma warning(disable:4996); #define __GETOPT_H__