2023-11-13 14:11:35 -05:00
/*
2024-03-10 16:55:40 -04:00
* Copyright ( C ) 2017 - 2024 Adrien Gesta - Fline
2023-11-13 14:11:35 -05:00
*
* 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 .
*/
/**
* @ file LibAAF / AAFIface / AAFIParser . c
* @ brief AAF processing
* @ author Adrien Gesta - Fline
* @ version 0.1
* @ date 27 june 2018
*
* @ ingroup AAFIface
* @ addtogroup AAFIface
*
*
*
*
* @ {
*/
2024-03-10 16:55:40 -04:00
# include <assert.h>
2023-11-13 14:11:35 -05:00
# include <errno.h>
2024-03-11 13:52:45 -04:00
# include <limits.h>
2023-11-13 14:11:35 -05:00
# include <locale.h>
2024-03-10 16:55:40 -04:00
# include <math.h>
2023-11-13 14:11:35 -05:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2024-03-10 16:55:40 -04:00
# include "aaf/AAFDefs/AAFClassDefUIDs.h"
# include "aaf/AAFDefs/AAFDataDefs.h"
# include "aaf/AAFDefs/AAFExtEnum.h"
# include "aaf/AAFDefs/AAFInterpolatorDefs.h"
# include "aaf/AAFDefs/AAFOPDefs.h"
# include "aaf/AAFDefs/AAFOperationDefs.h"
# include "aaf/AAFDefs/AAFParameterDefs.h"
# include "aaf/AAFDefs/AAFPropertyIDs.h"
# include "aaf/AAFDefs/AAFTypeDefUIDs.h"
2023-11-13 14:11:35 -05:00
# include "aaf/AAFDump.h"
2024-03-10 16:55:40 -04:00
# include "aaf/AAFIEssenceFile.h"
2023-11-13 14:11:35 -05:00
# include "aaf/AAFIParser.h"
# include "aaf/AAFIface.h"
# include "aaf/AAFToText.h"
2024-03-10 16:55:40 -04:00
# include "aaf/MediaComposer.h"
2023-11-13 14:11:35 -05:00
# include "aaf/ProTools.h"
# include "aaf/Resolve.h"
2024-03-10 16:55:40 -04:00
# include "aaf/log.h"
2023-11-13 14:11:35 -05:00
# include "aaf/utils.h"
# define debug(...) \
2024-03-19 15:59:04 -04:00
AAF_LOG ( aafi - > log , aafi , LOG_SRC_ID_AAF_IFACE , VERB_DEBUG , __VA_ARGS__ )
2023-11-13 14:11:35 -05:00
# define warning(...) \
2024-03-19 15:59:04 -04:00
AAF_LOG ( aafi - > log , aafi , LOG_SRC_ID_AAF_IFACE , VERB_WARNING , __VA_ARGS__ )
2023-11-13 14:11:35 -05:00
# define error(...) \
2024-03-19 15:59:04 -04:00
AAF_LOG ( aafi - > log , aafi , LOG_SRC_ID_AAF_IFACE , VERB_ERROR , __VA_ARGS__ )
2023-11-13 14:11:35 -05:00
static aafRational_t AAFI_DEFAULT_TC_EDIT_RATE = { 25 , 1 } ;
2024-03-10 16:55:40 -04:00
# 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 ; \
2024-02-14 18:49:10 -05:00
ctx . current_combined_clip_forced_length = 0 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
# 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 ) ;
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
parse_Mob ( AAF_Iface * aafi , aafObject * Mob , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
parse_CompositionMob ( AAF_Iface * aafi , aafObject * CompoMob , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
parse_SourceMob ( AAF_Iface * aafi , aafObject * SourceMob , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
parse_MobSlot ( AAF_Iface * aafi , aafObject * MobSlot , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
parse_TimelineMobSlot ( AAF_Iface * aafi , aafObject * TimelineMobSlot , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
parse_EventMobSlot ( AAF_Iface * aafi , aafObject * EventMobSlot , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
static int
parse_Component ( AAF_Iface * aafi , aafObject * Component , td * __ptd ) ;
2024-03-10 16:55:40 -04:00
2023-11-13 14:11:35 -05:00
static int
parse_Transition ( AAF_Iface * aafi , aafObject * Transition , td * __ptd ) ;
static int
2024-03-10 16:55:40 -04:00
parse_Segment ( AAF_Iface * aafi , aafObject * Segment , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
static int
parse_Filler ( AAF_Iface * aafi , aafObject * Filler , td * __ptd ) ;
static int
2024-03-10 16:55:40 -04:00
parse_SourceClip ( AAF_Iface * aafi , aafObject * SourceClip , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
static int
parse_Timecode ( AAF_Iface * aafi , aafObject * Timecode , td * __ptd ) ;
static int
2024-03-10 16:55:40 -04:00
parse_DescriptiveMarker ( AAF_Iface * aafi , aafObject * DescriptiveMarker , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
parse_Sequence ( AAF_Iface * aafi , aafObject * Sequence , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
static int
parse_Selector ( AAF_Iface * aafi , aafObject * Selector , td * __ptd ) ;
2024-03-10 16:55:40 -04:00
static int
parse_NestedScope ( AAF_Iface * aafi , aafObject * NestedScope , td * __ptd ) ;
static int
parse_OperationGroup ( AAF_Iface * aafi , aafObject * OpGroup , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
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 ) ;
2024-03-10 16:55:40 -04:00
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
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 ) ;
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
parse_DigitalImageDescriptor ( AAF_Iface * aafi , aafObject * DIDescriptor , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
parse_CDCIDescriptor ( AAF_Iface * aafi , aafObject * CDCIDescriptor , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
parse_Locator ( AAF_Iface * aafi , aafObject * Locator , td * __ptd ) ;
static int
parse_NetworkLocator ( AAF_Iface * aafi , aafObject * NetworkLocator , td * __ptd ) ;
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
parse_EssenceData ( AAF_Iface * aafi , aafObject * EssenceData , 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 [ ] ) ;
/* ****************************************************************************
* M o b
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
* Mob ( abs )
* |
* | - - > CompositionMob
* | - - > MasterMob
* ` - - > SourceMob
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
static int
parse_Mob ( AAF_Iface * aafi , aafObject * Mob , td * __ptd )
2023-11-13 14:11:35 -05:00
{
struct trace_dump __td ;
2024-03-10 16:55:40 -04:00
__td_set ( __td , __ptd , 1 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
int rc = 0 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * MobSlots = aaf_get_propertyValue ( Mob , PID_Mob_Slots , & AAFTypeID_MobSlotStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * MobSlot = NULL ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint32_t i = 0 ;
AAFI_foreach_ObjectInSet ( & MobSlot , MobSlots , i , __td )
{
parse_MobSlot ( aafi , MobSlot , & __td ) ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
goto end ;
err :
rc = - 1 ;
end :
return rc ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
static int
parse_CompositionMob ( AAF_Iface * aafi , aafObject * CompoMob , td * __ptd )
2023-11-13 14:11:35 -05:00
{
2024-03-10 16:55:40 -04:00
struct trace_dump __td ;
__td_set ( __td , __ptd , 0 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafUID_t * UsageCode = aaf_get_propertyValue ( CompoMob , PID_Mob_UsageCode , & AAFTypeID_UsageType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ) ;
aafObject * UserComments = aaf_get_propertyValue ( CompoMob , PID_Mob_UserComments , & AAFTypeID_TaggedValueStrongReferenceVector ) ;
if ( retrieve_UserComments ( aafi , UserComments , & aafi - > metadata ) < 0 ) {
TRACE_OBJ_WARNING ( aafi , CompoMob , & __td , " Error parsing Mob::UserComments " ) ;
} else {
TRACE_OBJ ( aafi , CompoMob , & __td ) ;
2023-11-13 14:11:35 -05:00
}
} else {
2024-03-10 16:55:40 -04:00
TRACE_OBJ_NO_SUPPORT ( aafi , CompoMob , & __td ) ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
return 0 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
static int
parse_SourceMob ( AAF_Iface * aafi , aafObject * SourceMob , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 0 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafMobID_t * MobID = aaf_get_propertyValue ( SourceMob , PID_Mob_MobID , & AAFTypeID_MobIDType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! MobID ) {
TRACE_OBJ_ERROR ( aafi , SourceMob , & __td , " Missing Mob::MobID " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
aafTimeStamp_t * CreationTime = aaf_get_propertyValue ( SourceMob , PID_Mob_CreationTime , & AAFTypeID_TimeStamp ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! CreationTime ) {
TRACE_OBJ_ERROR ( aafi , SourceMob , & __td , " Missing Mob::CreationTime " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * EssenceDesc = aaf_get_propertyValue ( SourceMob , PID_SourceMob_EssenceDescription , & AAFTypeID_EssenceDescriptorStrongReference ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! EssenceDesc ) {
TRACE_OBJ_ERROR ( aafi , SourceMob , & __td , " Missing SourceMob::EssenceDescription " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , SourceMob , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* 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 .
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( aafi - > ctx . current_audio_essence ) {
aafiAudioEssenceFile * audioEssenceFile = ( aafiAudioEssenceFile * ) aafi - > ctx . current_audio_essence ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
memcpy ( audioEssenceFile - > umid , MobID , sizeof ( aafMobID_t ) ) ;
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
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 ) ;
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
assert ( rc > 0 & & ( size_t ) rc < sizeof ( ( ( aafiAudioEssenceFile * ) 0 ) - > originationDate ) ) ;
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
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 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
assert ( rc > 0 & & ( size_t ) rc < sizeof ( ( ( aafiAudioEssenceFile * ) 0 ) - > originationTime ) ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
__td . ll [ __td . lv ] = 2 ;
parse_EssenceDescriptor ( aafi , EssenceDesc , & __td ) ;
__td . ll [ __td . lv ] = 1 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/* ****************************************************************************
* M o b S l o t
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* MobSlot ( abs )
* |
* | - - > TimelineMobSlot
* | - - > EventMobSlot
* ` - - > StaticMobSlot
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
static int
parse_MobSlot ( AAF_Iface * aafi , aafObject * MobSlot , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * Segment = aaf_get_propertyValue ( MobSlot , PID_MobSlot_Segment , & AAFTypeID_SegmentStrongReference ) ;
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
if ( ! Segment ) {
TRACE_OBJ_ERROR ( aafi , MobSlot , & __td , " Missing MobSlot::Segment " ) ;
return - 1 ;
}
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
if ( aafUIDCmp ( MobSlot - > Class - > ID , & AAFClassID_TimelineMobSlot ) ) {
if ( parse_TimelineMobSlot ( aafi , MobSlot , & __td ) < 0 ) {
return - 1 ;
2023-12-26 08:35:14 -05:00
}
2024-03-10 16:55:40 -04:00
} else if ( aafUIDCmp ( MobSlot - > Class - > ID , & AAFClassID_EventMobSlot ) ) {
if ( parse_EventMobSlot ( aafi , MobSlot , & __td ) < 0 ) {
return - 1 ;
2023-12-26 08:35:14 -05:00
}
2024-03-10 16:55:40 -04:00
} else {
TRACE_OBJ_NO_SUPPORT ( aafi , MobSlot , & __td ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
parse_Segment ( aafi , Segment , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
static int
parse_TimelineMobSlot ( AAF_Iface * aafi , aafObject * TimelineMobSlot , td * __ptd )
2023-11-13 14:11:35 -05:00
{
2024-03-10 16:55:40 -04:00
struct trace_dump __td ;
__td_set ( __td , __ptd , 0 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * ParentMob = aaf_get_ObjectAncestor ( TimelineMobSlot , & AAFClassID_Mob ) ;
if ( ! ParentMob ) {
TRACE_OBJ_ERROR ( aafi , TimelineMobSlot , & __td , " Could not retrieve parent Mob " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
uint32_t * track_num = aaf_get_propertyValue ( TimelineMobSlot , PID_MobSlot_PhysicalTrackNumber , & AAFTypeID_UInt32 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! track_num ) {
debug ( " Missing MobSlot::PhysicalTrackNumber " ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * Segment = aaf_get_propertyValue ( TimelineMobSlot , PID_MobSlot_Segment , & AAFTypeID_SegmentStrongReference ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! Segment ) {
TRACE_OBJ_ERROR ( aafi , TimelineMobSlot , & __td , " Missing MobSlot::Segment " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafWeakRef_t * dataDefWeakRef = aaf_get_propertyValue ( Segment , PID_Component_DataDefinition , & AAFTypeID_DataDefinitionWeakReference ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! dataDefWeakRef ) {
TRACE_OBJ_ERROR ( aafi , Segment , & __td , " Could not retrieve Component::DataDefinition from Segment child " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafUID_t * DataDefinition = aaf_get_DataIdentificationByWeakRef ( aafi - > aafd , dataDefWeakRef ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! DataDefinition ) {
TRACE_OBJ_ERROR ( aafi , TimelineMobSlot , & __td , " Could not retrieve DataDefinition " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafRational_t * edit_rate = aaf_get_propertyValue ( TimelineMobSlot , PID_TimelineMobSlot_EditRate , & AAFTypeID_Rational ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! edit_rate ) {
TRACE_OBJ_ERROR ( aafi , TimelineMobSlot , & __td , " Missing TimelineMobSlot::EditRate " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( aafUIDCmp ( ParentMob - > Class - > ID , & AAFClassID_CompositionMob ) ) {
/*
* 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
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* TODO : implement multiple TopLevel compositions support
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 . »
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( aafi - > ctx . TopLevelCompositionMob = = ParentMob /*!parentMobUsageCode || aafUIDCmp( parentMobUsageCode, &AAFUsage_TopLevel )*/ /*!aafi->ctx.is_inside_derivation_chain*/ ) {
TRACE_OBJ ( aafi , TimelineMobSlot , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint32_t tracknumber = ( track_num ) ? * track_num : ( aafi - > Audio - > track_count + 1 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiAudioTrack * track = aafi_newAudioTrack ( aafi ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
track - > number = tracknumber ;
track - > name = aaf_get_propertyValue ( TimelineMobSlot , PID_MobSlot_SlotName , & AAFTypeID_String ) ;
track - > edit_rate = edit_rate ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > Audio - > track_count + = 1 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_track = track ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* Avid Media Composer
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
void * TimelineMobAttributeList = aaf_get_propertyValue ( TimelineMobSlot , aaf_get_PropertyIDByName ( aafi - > aafd , " TimelineMobAttributeList " ) , & AAFTypeID_TaggedValueStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( TimelineMobAttributeList ) {
int32_t * solo = aaf_get_TaggedValueByName ( aafi - > aafd , TimelineMobAttributeList , " AudioMixerCompSolo " , & AAFTypeID_Int32 ) ;
int32_t * mute = aaf_get_TaggedValueByName ( aafi - > aafd , TimelineMobAttributeList , " AudioMixerCompMute " , & AAFTypeID_Int32 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( solo & & * solo ) {
track - > solo = 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , TimelineMobSlot , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint32_t tracknumber = ( track_num ) ? * track_num : 1 /* current implementation supports only one video track */ ;
aafiVideoTrack * track = aafi_newVideoTrack ( aafi ) ;
track - > number = tracknumber ;
track - > name = aaf_get_propertyValue ( TimelineMobSlot , PID_MobSlot_SlotName , & AAFTypeID_String ) ;
track - > edit_rate = edit_rate ;
} else if ( aafUIDCmp ( DataDefinition , & AAFDataDef_Timecode ) | |
aafUIDCmp ( DataDefinition , & AAFDataDef_LegacyTimecode ) ) {
TRACE_OBJ ( aafi , TimelineMobSlot , & __td ) ;
} else if ( aafUIDCmp ( DataDefinition , & AAFDataDef_DescriptiveMetadata ) ) {
/*
* Avid Media Composer 23.12 , markers with duration ( no - duration markers are held by AAFClassID_EventMobSlot )
*
│ 0417 9 │ └ ─ ─ ◻ AAFClassID_TimelineMobSlot [ slot : 3003 track : 12 ] ( DataDef : AAFDataDef_DescriptiveMetadata ) : Segmentation
│ 01 946 │ └ ─ ─ ◻ AAFClassID_Sequence ( Length : 4 )
│ 03031 │ └ ─ ─ ◻ AAFClassID_DescriptiveMarker ( Length : 4 ) ( MetaProps : CommentMarkerAttributeList [ 0xffd4 ] CommentMarkerColor [ 0xffdb ] CommentMarkerUSer [ 0xffda ] CommentMarkerDate [ 0xffd9 ] CommentMarkerTime [ 0xffd8 ] )
*/
TRACE_OBJ ( aafi , TimelineMobSlot , & __td ) ;
} 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 ) ) {
/*
* 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 .
*/
if ( aafi - > ctx . current_audio_essence ) {
aafPosition_t * Origin = aaf_get_propertyValue ( TimelineMobSlot , PID_TimelineMobSlot_Origin , & AAFTypeID_PositionType ) ;
if ( ! Origin ) {
TRACE_OBJ_ERROR ( aafi , TimelineMobSlot , & __td , " Missing TimelineMobSlot::Origin " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , TimelineMobSlot , & __td ) ;
aafiAudioEssenceFile * audioEssenceFile = ( aafiAudioEssenceFile * ) aafi - > ctx . current_audio_essence ;
audioEssenceFile - > sourceMobSlotOrigin = * Origin ;
audioEssenceFile - > sourceMobSlotEditRate = edit_rate ;
} else {
TRACE_OBJ ( aafi , TimelineMobSlot , & __td ) ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
} else {
/*
* AAFClassID_MasterMob and AAFClassID_SourceMob are accessed directly from TimelineMobSlot > SourceClip
*/
TRACE_OBJ_NO_SUPPORT ( aafi , TimelineMobSlot , & __td ) ;
return - 1 ;
}
return 0 ;
}
static int
parse_EventMobSlot ( AAF_Iface * aafi , aafObject * EventMobSlot , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 0 ) ;
aafRational_t * edit_rate = aaf_get_propertyValue ( EventMobSlot , PID_EventMobSlot_EditRate , & AAFTypeID_Rational ) ;
if ( ! edit_rate ) {
TRACE_OBJ_ERROR ( aafi , EventMobSlot , & __td , " Missing EventMobSlot::EditRate " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , EventMobSlot , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_markers_edit_rate = edit_rate ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
/* ****************************************************************************
* 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 )
2023-11-13 14:11:35 -05:00
{
2024-03-10 16:55:40 -04:00
struct trace_dump __td ;
__td_set ( __td , __ptd , 0 ) ;
if ( aafUIDCmp ( Component - > Class - > ID , & AAFClassID_Transition ) ) {
parse_Transition ( aafi , Component , & __td ) ;
} else {
parse_Segment ( aafi , Component , & __td ) ;
}
return 0 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
static int
parse_Transition ( AAF_Iface * aafi , aafObject * Transition , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* 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 .
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafWeakRef_t * dataDefWeakRef = aaf_get_propertyValue ( Transition , PID_Component_DataDefinition , & AAFTypeID_DataDefinitionWeakReference ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! dataDefWeakRef ) {
TRACE_OBJ_ERROR ( aafi , Transition , & __td , " Missing Component::DataDefinition. " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafUID_t * DataDefinition = aaf_get_DataIdentificationByWeakRef ( aafi - > aafd , dataDefWeakRef ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! DataDefinition ) {
TRACE_OBJ_ERROR ( aafi , Transition , & __td , " Could not retrieve DataDefinition " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! aafUIDCmp ( DataDefinition , & AAFDataDef_Sound ) & &
! aafUIDCmp ( DataDefinition , & AAFDataDef_LegacySound ) ) {
TRACE_OBJ_ERROR ( aafi , Transition , & __td , " Current implementation does not support video Transitions " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
int64_t * length = aaf_get_propertyValue ( Transition , PID_Component_Length , & AAFTypeID_LengthType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! length ) {
TRACE_OBJ_ERROR ( aafi , Transition , & __td , " Missing Component::Length " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * OpGroup = aaf_get_propertyValue ( Transition , PID_Transition_OperationGroup , & AAFTypeID_OperationGroupStrongReference ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! OpGroup ) {
TRACE_OBJ_ERROR ( aafi , Transition , & __td , " Missing Transition::OperationGroup " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
aafPosition_t * cutPoint = aaf_get_propertyValue ( Transition , PID_Transition_CutPoint , & AAFTypeID_PositionType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! cutPoint ) {
/* not encountered though */
debug ( " Missing Transition::CutPoint : setting cut point to Transition::Length/2 " ) ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
uint32_t fadeType = 0 ;
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , Transition , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiTransition * Trans = aafi_newTransition ( aafi , aafi - > ctx . current_track ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
Trans - > len = * length ;
Trans - > flags = fadeType ;
Trans - > cut_pt = ( cutPoint ) ? * cutPoint : ( Trans - > len / 2 ) ;
2023-11-13 14:11:35 -05:00
/*
2024-03-10 16:55:40 -04:00
* 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 ) »
2023-11-13 14:11:35 -05:00
*/
2024-03-10 16:55:40 -04:00
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 ;
}
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_transition = Trans ;
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
parse_OperationGroup ( aafi , OpGroup , & __td ) ;
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_transition = NULL ;
aafi - > ctx . current_track - > current_pos - = * length ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
int
parse_Segment ( AAF_Iface * aafi , aafObject * Segment , td * __ptd )
2023-11-13 14:11:35 -05:00
{
2024-03-10 16:55:40 -04:00
struct trace_dump __td ;
__td_set ( __td , __ptd , 0 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ?
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
__td . lv + + ;
TRACE_OBJ_NO_SUPPORT ( aafi , Segment , & __td ) ;
__td . lv - - ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return - 1 ;
} else {
__td . lv + + ;
TRACE_OBJ_NO_SUPPORT ( aafi , Segment , & __td ) ;
__td . lv - - ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
return 0 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
static int
parse_Filler ( AAF_Iface * aafi , aafObject * Filler , td * __ptd )
2023-11-13 14:11:35 -05:00
{
2024-03-10 16:55:40 -04:00
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
__td . eob = 1 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafWeakRef_t * dataDefWeakRef = aaf_get_propertyValue ( Filler , PID_Component_DataDefinition , & AAFTypeID_DataDefinitionWeakReference ) ;
if ( ! dataDefWeakRef ) {
TRACE_OBJ_ERROR ( aafi , Filler , & __td , " Missing Component::DataDefinition. " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
aafUID_t * DataDefinition = aaf_get_DataIdentificationByWeakRef ( aafi - > aafd , dataDefWeakRef ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! DataDefinition ) {
TRACE_OBJ_ERROR ( aafi , Filler , & __td , " Could not retrieve DataDefinition " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
/*
* 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 ?
*/
int64_t * length = aaf_get_propertyValue ( Filler , PID_Component_Length , & AAFTypeID_LengthType ) ;
if ( ! length ) {
TRACE_OBJ_ERROR ( aafi , Filler , & __td , " Missing Component::Length " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , Filler , & __td ) ;
return 0 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
static int
parse_SourceClip ( AAF_Iface * aafi , aafObject * SourceClip , td * __ptd )
2023-11-13 14:11:35 -05:00
{
2024-03-10 16:55:40 -04:00
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
aafWeakRef_t * dataDefWeakRef = aaf_get_propertyValue ( SourceClip , PID_Component_DataDefinition , & AAFTypeID_DataDefinitionWeakReference ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! dataDefWeakRef ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Missing Component::DataDefinition. " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
aafUID_t * DataDefinition = aaf_get_DataIdentificationByWeakRef ( aafi - > aafd , dataDefWeakRef ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! DataDefinition ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Could not retrieve DataDefinition " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
aafObject * ParentMob = aaf_get_ObjectAncestor ( SourceClip , & AAFClassID_Mob ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! ParentMob ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Could not retrieve parent Mob " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
aafMobID_t * parentMobID = aaf_get_propertyValue ( ParentMob , PID_Mob_MobID , & AAFTypeID_MobIDType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! parentMobID ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Missing parent Mob::MobID " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafUID_t * parentMobUsageCode = aaf_get_propertyValue ( ParentMob , PID_Mob_UsageCode , & AAFTypeID_UsageType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! parentMobUsageCode ) {
debug ( " Missing parent Mob Mob::UsageCode " ) ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
aafMobID_t * sourceID = aaf_get_propertyValue ( SourceClip , PID_SourceReference_SourceID , & AAFTypeID_MobIDType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint32_t * SourceMobSlotID = aaf_get_propertyValue ( SourceClip , PID_SourceReference_SourceMobSlotID , & AAFTypeID_UInt32 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! SourceMobSlotID ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Missing SourceReference::SourceMobSlotID " ) ;
2023-11-13 14:11:35 -05:00
return - 1 ;
}
2024-03-10 16:55:40 -04:00
/*
* TODO : handle SourceReference : : ChannelIDs and SourceReference : : MonoSourceSlotIDs
* ( Multi - channels )
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * targetMob = NULL ;
aafObject * targetMobSlot = NULL ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ?
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
// sourceID = parentMobID;
// targetMob = ParentMob;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
debug ( " SourceReference::SourceID is missing or NULL " ) ;
} else {
targetMob = aaf_get_MobByID ( aafi - > aafd - > Mobs , sourceID ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! targetMob ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Could not retrieve target Mob by ID : %s " , aaft_MobIDToText ( sourceID ) ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * targetMobSlots = aaf_get_propertyValue ( targetMob , PID_Mob_Slots , & AAFTypeID_MobSlotStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! targetMobSlots ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Missing target Mob::Slots " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
targetMobSlot = aaf_get_MobSlotBySlotID ( targetMobSlots , * SourceMobSlotID ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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
2023-11-13 14:11:35 -05:00
*/
2024-03-10 16:55:40 -04:00
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Could not retrieve target MobSlot ID : %u " , * SourceMobSlotID ) ;
return - 1 ;
}
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/* *** Clip *** */
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( aafUIDCmp ( ParentMob - > Class - > ID , & AAFClassID_CompositionMob ) ) {
int64_t * length = aaf_get_propertyValue ( SourceClip , PID_Component_Length , & AAFTypeID_LengthType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! length ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Missing Component::Length " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
int64_t * startTime = aaf_get_propertyValue ( SourceClip , PID_SourceClip_StartTime , & AAFTypeID_PositionType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! startTime ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Missing SourceClip::StartTime " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( aafUIDCmp ( DataDefinition , & AAFDataDef_Sound ) | |
aafUIDCmp ( DataDefinition , & AAFDataDef_LegacySound ) ) {
if ( aafi - > ctx . TopLevelCompositionMob = = ParentMob /*!parentMobUsageCode || aafUIDCmp( parentMobUsageCode, &AAFUsage_TopLevel )*/ ) {
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 )
│ 02 816 │ │ ├ ─ ─ ◻ AAFClassID_SourceClip ( Length : 516000 )
│ 02 821 │ │ │ └ ─ ─ ◻ AAFClassID_MasterMob ( UsageCode : n / a ) : 7
│ 04622 │ │ │ └ ─ ─ ◻ AAFClassID_TimelineMobSlot [ slot : 1 track : 1 ] ( DataDef : AAFDataDef_Sound )
│ 031 85 │ │ │ └ ─ ─ ◻ AAFClassID_SourceClip ( Length : 523723 )
│ 04346 │ │ │ └ ─ ─ ◻ AAFClassID_SourceMob ( UsageCode : n / a ) : 7
│ 013 93 │ │ │ └ ─ ─ ◻ 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 )
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 )
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_clip - > essencePointerList - > essenceChannel = 0 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
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
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiAudioClip * audioClip = aafi_newAudioClip ( aafi , aafi - > ctx . current_track ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiTimelineItem * timelineItem = audioClip - > timelineItem ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_track - > current_pos + = audioClip - > len ;
aafi - > ctx . current_track - > clipCount + + ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_clip_gain_is_used + + ;
aafi - > ctx . current_clip_variable_gain_is_used + + ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* ComponentAttributeList is non - standard , but used by Avid Media Composer
* and Davinci Resolve to attach Clip Notes .
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
void * ComponentAttributeList = aaf_get_propertyValue ( SourceClip , aaf_get_PropertyIDByName ( aafi - > aafd , " ComponentAttributeList " ) , & AAFTypeID_TaggedValueStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ComponentAttributeList ) {
char * comment = aaf_get_TaggedValueByName ( aafi - > aafd , ComponentAttributeList , " _COMMENT " , & AAFTypeID_String ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( comment ) {
aafiMetaData * meta = aafi_newMetadata ( aafi , & audioClip - > metadata ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! meta ) {
warning ( " Could not create new Metadata. " ) ;
} else {
meta - > text = comment ;
meta - > name = laaf_util_c99strdup ( " _COMMENT " ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! meta - > name ) {
error ( " Could not duplicate meta name : %s " , " _COMMENT " ) ;
aafiMetaData * tmp = meta - > next ;
aafi_freeMetadata ( & meta ) ;
audioClip - > metadata = tmp ;
}
}
}
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_clip = audioClip ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ) {
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 ) ) {
/* 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 .
*
│ 0270 9 │ │ ├ ─ ─ ◻ AAFClassID_SourceClip ( Length : 183 )
│ 02723 │ │ │ └ ─ ─ ◻ AAFClassID_CompositionMob ( UsageCode : AAFUsage_SubClip ) : plato 8 1 ere . Copy .01 . new .06 ( MetaProps : SubclipBegin [ 0xfff6 ] SubclipFullLength [ 0xfff7 ] MobAttributeList [ 0xfff9 ] )
│ 0447 8 │ │ │ └ ─ ─ ◻ AAFClassID_TimelineMobSlot [ slot : 2 track : 2 ] ( DataDef : AAFDataDef_Sound )
│ 02 978 │ │ │ └ ─ ─ ◻ AAFClassID_SourceClip ( Length : 681 )
│ 02 983 │ │ │ └ ─ ─ ◻ 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
│ 031 88 │ │ │ └ ─ ─ ◻ AAFClassID_SourceClip ( Length : 681 )
│ 04305 │ │ │ └ ─ ─ ◻ AAFClassID_SourceMob ( UsageCode : n / a ) : FTVHD - X400 - 0946. PHYS ( MetaProps : MobAttributeList [ 0xfff9 ] )
│ 01342 │ │ │ └ ─ ─ ◻ AAFClassID_PCMDescriptor ( MetaProps : DataOffset [ 0xffde ] )
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_clip - > subClipName = aaf_get_propertyValue ( ParentMob , PID_Mob_Name , & AAFTypeID_String ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! aafi - > ctx . current_clip - > subClipName ) {
debug ( " Missing parent Mob::Name (sub-clip name) " ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * UserComments = aaf_get_propertyValue ( ParentMob , PID_Mob_UserComments , & AAFTypeID_TaggedValueStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( retrieve_UserComments ( aafi , UserComments , & aafi - > ctx . current_clip - > metadata ) < 0 ) {
warning ( " Error parsing parent Mob::UserComments " ) ;
}
} else if ( aafUIDCmp ( parentMobUsageCode , & AAFUsage_AdjustedClip ) ) {
// if ( aafi->ctx.current_adjusted_clip_gain ) {
2024-03-19 15:59:04 -04:00
// aafi_applyGainOffset( aafi, &aafi->ctx.current_clip->gain, aafi->ctx.current_adjusted_clip_gain );
2024-03-10 16:55:40 -04:00
// 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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( targetMob & & aafUIDCmp ( targetMob - > Class - > ID , & AAFClassID_MasterMob ) ) {
if ( ! targetMobSlot ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Missing target MobSlot " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , SourceClip , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
__td . lv + + ;
TRACE_OBJ ( aafi , targetMob , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
parse_MobSlot ( aafi , targetMobSlot , & __td ) ;
} else if ( targetMob & & aafUIDCmp ( targetMob - > Class - > ID , & AAFClassID_CompositionMob ) ) {
/*
* If SourceClip points to a CompositionMob instead of a MasterMob , we
* are at the begining ( or inside ) a derivation chain .
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , SourceClip , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
__td . lv + + ;
TRACE_OBJ ( aafi , targetMob , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
} 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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( aafi - > Video - > Tracks - > timelineItems ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Current implementation supports only one video clip " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/* Add the new clip */
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiVideoClip * videoClip = aafi_newVideoClip ( aafi , aafi - > Video - > Tracks ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiTimelineItem * timelineItem = videoClip - > timelineItem ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
timelineItem - > pos = aafi - > Video - > Tracks - > current_pos ;
timelineItem - > len = * length ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
videoClip - > pos = aafi - > Video - > Tracks - > current_pos ;
videoClip - > len = * length ;
videoClip - > essence_offset = * startTime ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > Video - > Tracks - > current_pos + = videoClip - > len ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_video_clip = videoClip ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( targetMob & & aafUIDCmp ( targetMob - > Class - > ID , & AAFClassID_MasterMob ) ) {
if ( ! targetMobSlot ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Missing target MobSlot " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , SourceClip , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
__td . lv + + ;
TRACE_OBJ ( aafi , targetMob , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
}
}
2024-03-10 16:55:40 -04:00
/* *** Essence *** */
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
else if ( aafUIDCmp ( ParentMob - > Class - > ID , & AAFClassID_MasterMob ) ) {
aafMobID_t * masterMobID = aaf_get_propertyValue ( ParentMob , PID_Mob_MobID , & AAFTypeID_MobIDType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! masterMobID ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Missing parent Mob::MobID " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * ParentMobSlot = aaf_get_ObjectAncestor ( SourceClip , & AAFClassID_MobSlot ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! ParentMobSlot ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Could not retrieve parent MobSlot " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
uint32_t * masterMobSlotID = aaf_get_propertyValue ( ParentMobSlot , PID_MobSlot_SlotID , & AAFTypeID_UInt32 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint32_t * essenceChannelNum = aaf_get_propertyValue ( ParentMobSlot , PID_MobSlot_PhysicalTrackNumber , & AAFTypeID_UInt32 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( aafUIDCmp ( DataDefinition , & AAFDataDef_Sound ) | |
aafUIDCmp ( DataDefinition , & AAFDataDef_LegacySound ) ) {
if ( ! aafi - > ctx . current_clip ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " aafi->ctx.current_clip not set " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
/*
* Check if this Essence has already been retrieved
*/
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 ;
}
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
/* new Essence, carry on. */
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
audioEssenceFile = aafi_newAudioEssence ( aafi ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
audioEssenceFile - > masterMobSlotID = * masterMobSlotID ;
audioEssenceFile - > masterMobID = masterMobID ;
audioEssenceFile - > name = aaf_get_propertyValue ( ParentMob , PID_Mob_Name , & AAFTypeID_String ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( audioEssenceFile - > name = = NULL ) {
debug ( " Missing parent Mob::Name (essence file name) " ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
audioEssenceFile - > sourceMobSlotID = * SourceMobSlotID ;
audioEssenceFile - > sourceMobID = sourceID ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * SourceMob = aaf_get_MobByID ( aafi - > aafd - > Mobs , audioEssenceFile - > sourceMobID ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! SourceMob ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Could not retrieve SourceMob by ID : %s " , aaft_MobIDToText ( audioEssenceFile - > sourceMobID ) ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_audio_essence = audioEssenceFile ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
void * MobUserComments = aaf_get_propertyValue ( ParentMob , PID_Mob_UserComments , & AAFTypeID_TaggedValueStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
audioEssenceFile - > SourceMob = SourceMob ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * EssenceData = aaf_get_EssenceDataByMobID ( aafi - > aafd , audioEssenceFile - > sourceMobID ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( EssenceData )
__td . ll [ __td . lv ] = 2 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
parse_Mob ( aafi , SourceMob , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( EssenceData )
__td . ll [ __td . lv ] = 1 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( EssenceData ) {
/* If EssenceData was found, it means essence is embedded */
parse_EssenceData ( aafi , EssenceData , & __td ) ;
__td . ll [ __td . lv ] = 0 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi_build_unique_audio_essence_name ( aafi , audioEssenceFile ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ) ) {
if ( ! aafi - > ctx . current_video_clip ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " aafi->ctx.current_video_clip not set " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* Check if this Essence has already been retrieved
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiVideoEssence * videoEssenceFile = NULL ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
}
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
/* new Essence, carry on. */
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
videoEssenceFile = aafi_newVideoEssence ( aafi ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_video_clip - > Essence = videoEssenceFile ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
videoEssenceFile - > masterMobSlotID = * masterMobSlotID ;
videoEssenceFile - > masterMobID = masterMobID ;
videoEssenceFile - > name = aaf_get_propertyValue ( ParentMob , PID_Mob_Name , & AAFTypeID_String ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( videoEssenceFile - > name = = NULL ) {
debug ( " Missing parent Mob::Name (essence file name) " ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
videoEssenceFile - > sourceMobSlotID = * SourceMobSlotID ;
videoEssenceFile - > sourceMobID = sourceID ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , SourceClip , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * SourceMob = aaf_get_MobByID ( aafi - > aafd - > Mobs , videoEssenceFile - > sourceMobID ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! SourceMob ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Could not retrieve SourceMob by ID : %s " , aaft_MobIDToText ( videoEssenceFile - > sourceMobID ) ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
videoEssenceFile - > SourceMob = SourceMob ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_video_essence = videoEssenceFile ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * EssenceData = aaf_get_EssenceDataByMobID ( aafi - > aafd , videoEssenceFile - > sourceMobID ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
parse_Mob ( aafi , SourceMob , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( EssenceData ) {
/*
* It means essence is embedded , otherwise it ' s not .
*/
parse_EssenceData ( aafi , EssenceData , & __td ) ;
}
2023-11-13 14:11:35 -05:00
/*
2024-03-10 16:55:40 -04:00
* No need to check for uniqueness , current version supports only one video clip .
2023-11-13 14:11:35 -05:00
*/
2024-03-10 16:55:40 -04:00
videoEssenceFile - > unique_name = laaf_util_c99strdup ( videoEssenceFile - > name ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! videoEssenceFile - > unique_name ) {
TRACE_OBJ_ERROR ( aafi , SourceClip , & __td , " Could not duplicate video essence unique name : %s " , videoEssenceFile - > name ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
static int
parse_Timecode ( AAF_Iface * aafi , aafObject * Timecode , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
__td . eob = 1 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafPosition_t * tc_start = aaf_get_propertyValue ( Timecode , PID_Timecode_Start , & AAFTypeID_PositionType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( tc_start = = NULL ) {
TRACE_OBJ_ERROR ( aafi , Timecode , & __td , " Missing Timecode::Start " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint16_t * tc_fps = aaf_get_propertyValue ( Timecode , PID_Timecode_FPS , & AAFTypeID_UInt16 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( tc_fps = = NULL ) {
TRACE_OBJ_ERROR ( aafi , Timecode , & __td , " Missing Timecode::FPS " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint8_t * tc_drop = aaf_get_propertyValue ( Timecode , PID_Timecode_Drop , & AAFTypeID_UInt8 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( tc_drop = = NULL ) {
TRACE_OBJ_ERROR ( aafi , Timecode , & __td , " Missing Timecode::Drop " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/* TODO this should be retrieved directly from TimelineMobSlot */
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * ParentMobSlot = aaf_get_ObjectAncestor ( Timecode , & AAFClassID_MobSlot ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! ParentMobSlot ) {
TRACE_OBJ_ERROR ( aafi , Timecode , & __td , " Could not retrieve parent MobSlot " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafRational_t * tc_edit_rate = aaf_get_propertyValue ( ParentMobSlot , PID_TimelineMobSlot_EditRate , & AAFTypeID_Rational ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( tc_edit_rate = = NULL ) {
TRACE_OBJ_ERROR ( aafi , Timecode , & __td , " Missing parent TimelineMobSlot::EditRate " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( aafi - > Timecode ) {
TRACE_OBJ_WARNING ( aafi , Timecode , & __td , " Timecode was already set, ignoring (%lu, %u fps) " , * tc_start , * tc_fps ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiTimecode * tc = calloc ( 1 , sizeof ( aafiTimecode ) ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! tc ) {
TRACE_OBJ_ERROR ( aafi , Timecode , & __td , " Out of memory " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
tc - > start = * tc_start ;
tc - > fps = * tc_fps ;
tc - > drop = * tc_drop ;
tc - > edit_rate = tc_edit_rate ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi - > Timecode = tc ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , Timecode , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
static int
parse_DescriptiveMarker ( AAF_Iface * aafi , aafObject * DescriptiveMarker , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafPosition_t * start = aaf_get_propertyValue ( DescriptiveMarker , PID_Event_Position , & AAFTypeID_PositionType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , DescriptiveMarker , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! name ) {
/* Avid Media Composer 23.12 */
name = aaf_get_propertyValue ( DescriptiveMarker , aaf_get_PropertyIDByName ( aafi - > aafd , " CommentMarkerUSer " ) , & AAFTypeID_String ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint16_t * RGBColor = NULL ;
aafProperty * RGBColorProp = aaf_get_property ( DescriptiveMarker , aaf_get_PropertyIDByName ( aafi - > aafd , " CommentMarkerColor " ) ) ;
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
if ( RGBColorProp ) {
if ( RGBColorProp - > len ! = sizeof ( uint16_t ) * 3 ) {
error ( " CommentMarkerColor has wrong size: %u " , RGBColorProp - > len ) ;
} else {
RGBColor = RGBColorProp - > val ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/* 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 ) ;
}
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi_newMarker ( aafi , aafi - > ctx . current_markers_edit_rate , * start , ( ( length ) ? * length : 0 ) , name , comment , & RGBColor ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
static int
parse_Sequence ( AAF_Iface * aafi , aafObject * Sequence , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * Component = NULL ;
aafObject * Components = aaf_get_propertyValue ( Sequence , PID_Sequence_Components , & AAFTypeID_ComponentStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! Components ) {
TRACE_OBJ_ERROR ( aafi , Sequence , & __td , " Missing Sequence::Components " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , Sequence , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* " 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 .
*
│ 0200 9 │ │ │ ├ ─ ─ ◻ AAFClassID_OperationGroup ( OpIdent : Audio Warp ; Length : 168 ) ( MetaProps : ComponentAttributeList [ 0xffc9 ] )
│ 022 83 │ │ │ │ ├ ─ ─ ◻ AAFClassID_ConstantValue ( ParamDef : AvidMotionInputFormat ; Type : AAFTypeID_Int32 ) : 2
│ 022 83 │ │ │ │ ├ ─ ─ ◻ AAFClassID_ConstantValue ( ParamDef : AAFParameterDef_SpeedRatio ; Type : AAFTypeID_Rational ) : 1 / 2
│ 022 83 │ │ │ │ ├ ─ ─ ◻ AAFClassID_ConstantValue ( ParamDef : AvidPhase ; Type : AAFTypeID_Int32 ) : 0
│ 022 83 │ │ │ │ ├ ─ ─ ◻ AAFClassID_ConstantValue ( ParamDef : AvidMotionOutputFormat ; Type : AAFTypeID_Int32 ) : 0
│ 022 83 │ │ │ │ └ ─ ─ ◻ AAFClassID_ConstantValue ( ParamDef : AvidMotionPulldown ; Type : AAFTypeID_Int32 ) : 0
│ 0162 8 │ │ │ │ └ ─ ─ ◻ AAFClassID_Sequence ( Length : 336 ) ( MetaProps : ComponentAttributeList [ 0xffc9 ] )
│ 011 95 │ │ │ │ └ ─ ─ ◻ AAFClassID_SourceClip ( Length : 336 )
│ 011 98 │ │ │ │ └ ─ ─ ◻ 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 )
│ 0162 8 │ │ │ │ └ ─ ─ ◻ AAFClassID_Sequence ( Length : 576 )
│ 0135 9 │ │ │ │ └ ─ ─ ◻ AAFClassID_SourceClip ( Length : 576 )
│ 00272 │ │ │ │ ├ ─ ─ ◻ AAFClassID_SourceMob ( UsageCode : n / a ) ( MetaProps : MobAttributeList [ 0xfff9 ] )
│ 02 806 │ │ │ │ │ ├ ─ ─ ◻ 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 )
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
void * ComponentAttributeList = aaf_get_propertyValue ( Sequence , aaf_get_PropertyIDByName ( aafi - > aafd , " ComponentAttributeList " ) , & AAFTypeID_TaggedValueStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ) ;
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
if ( rateNum & & rateDenom ) {
aafi - > ctx . avid_warp_clip_edit_rate = malloc ( sizeof ( aafRational_t ) ) ;
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
if ( ! aafi - > ctx . avid_warp_clip_edit_rate ) {
error ( " Out of memory " ) ;
2023-11-13 14:11:35 -05:00
return - 1 ;
}
2024-03-10 16:55:40 -04:00
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 ) ;
}
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint32_t i = 0 ;
AAFI_foreach_ObjectInSet ( & Component , Components , i , __td )
{
parse_Component ( aafi , Component , & __td ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
free ( aafi - > ctx . avid_warp_clip_edit_rate ) ;
aafi - > ctx . avid_warp_clip_edit_rate = NULL ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 )
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * Selected = aaf_get_propertyValue ( Selector , PID_Selector_Selected , & AAFTypeID_SegmentStrongReference ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! Selected ) {
TRACE_OBJ_ERROR ( aafi , Selector , & __td , " Missing Selector::Selected " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , Selector , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * Alternates = aaf_get_propertyValue ( Selector , PID_Selector_Alternates , & AAFTypeID_SegmentStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( Alternates ) {
__td . lv + + ;
TRACE_OBJ_INFO ( aafi , Alternates , & __td , " Selector Alternates (dropping) " ) ;
__td . lv - - ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* 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 .
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
void * ComponentAttributeList = aaf_get_propertyValue ( Selector , aaf_get_PropertyIDByName ( aafi - > aafd , " ComponentAttributeList " ) , & AAFTypeID_TaggedValueStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ComponentAttributeList ) {
int32_t * disabledClip = aaf_get_TaggedValueByName ( aafi - > aafd , ComponentAttributeList , " _DISABLE_CLIP_FLAG " , & AAFTypeID_Int32 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( disabledClip ) {
if ( * disabledClip ) {
aafi - > ctx . current_clip_is_muted = 1 ;
}
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
/*
* 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 ) ;
2023-12-26 08:35:14 -05:00
} else {
2024-03-10 16:55:40 -04:00
return parse_Segment ( aafi , Selected , & __td ) ;
2023-11-13 14:11:35 -05:00
}
}
2024-03-10 16:55:40 -04:00
} else {
/*
* without specific software implementation , we stick to Selected Object
* and forget about any Alternates Objects .
*/
return parse_Segment ( aafi , Selected , & __td ) ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
static int
parse_NestedScope ( AAF_Iface * aafi , aafObject * NestedScope , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* NestedScope seems to be only used for video clips in Avid Media Composer .
* Not sure how to handle it . . .
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * Slot = NULL ;
aafObject * Slots = aaf_get_propertyValue ( NestedScope , PID_NestedScope_Slots , & AAFTypeID_SegmentStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! Slots ) {
TRACE_OBJ_ERROR ( aafi , NestedScope , & __td , " Missing NestedScope::Slots " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , NestedScope , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint32_t i = 0 ;
AAFI_foreach_ObjectInSet ( & Slot , Slots , i , __td )
{
parse_Segment ( aafi , Slot , & __td ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
static int
parse_OperationGroup ( AAF_Iface * aafi , aafObject * OpGroup , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
if ( ! aaf_get_property ( OpGroup , PID_OperationGroup_InputSegments ) & &
! aaf_get_property ( OpGroup , PID_OperationGroup_Parameters ) ) {
__td . eob = 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * ParentMob = aaf_get_ObjectAncestor ( OpGroup , & AAFClassID_Mob ) ;
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
if ( ! ParentMob ) {
TRACE_OBJ_ERROR ( aafi , OpGroup , & __td , " Could not retrieve parent Mob " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
int rc = 0 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafWeakRef_t * OperationDefWeakRef = aaf_get_propertyValue ( OpGroup , PID_OperationGroup_Operation , & AAFTypeID_OperationDefinitionWeakReference ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! OperationDefWeakRef ) {
TRACE_OBJ_ERROR ( aafi , OpGroup , & __td , " Missing OperationGroup::Operation " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafUID_t * OperationIdentification = aaf_get_OperationIdentificationByWeakRef ( aafi - > aafd , OperationDefWeakRef ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! OperationIdentification ) {
TRACE_OBJ_ERROR ( aafi , OpGroup , & __td , " Could not retrieve OperationIdentification " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* 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 .
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * OperationGroupParent = OpGroup - > Parent ;
while ( OperationGroupParent & & aafUIDCmp ( OperationGroupParent - > Class - > ID , & AAFClassID_OperationGroup ) ) {
OperationGroupParent = OperationGroupParent - > Parent ;
}
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
if ( ! OperationGroupParent ) {
error ( " OperationGroup has no parent ! " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , OpGroup , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiTransition * Trans = aafi - > ctx . current_transition ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* 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 ) .
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
Trans - > flags | = AAFI_TRANS_SINGLE_CURVE ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * Param = NULL ;
aafObject * Parameters = aaf_get_propertyValue ( OpGroup , PID_OperationGroup_Parameters , & AAFTypeID_ParameterStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint32_t i = 0 ;
AAFI_foreach_ObjectInSet ( & Param , Parameters , i , __td )
{
parse_Parameter ( aafi , Param , & __td ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* 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 .
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
void * ComponentAttributeList = aaf_get_propertyValue ( OpGroup , aaf_get_PropertyIDByName ( aafi - > aafd , " ComponentAttributeList " ) , & AAFTypeID_TaggedValueStrongReferenceVector ) ;
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
if ( ComponentAttributeList ) {
int32_t * curveType = aaf_get_TaggedValueByName ( aafi - > aafd , ComponentAttributeList , " _ATN_AUDIO_DISSOLVE_CURVETYPE " , & AAFTypeID_Int32 ) ;
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
}
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! ( Trans - > flags & AAFI_INTERPOL_MASK ) ) {
debug ( " Setting fade interpolation to default Linear " ) ;
Trans - > flags | = AAFI_INTERPOL_LINEAR ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi_dump_obj ( aafi , NULL , & __td , 0 , NULL , - 1 , " " ) ;
} else if ( aafUIDCmp ( OperationIdentification , & AAFOperationDef_AudioChannelCombiner ) ) {
TRACE_OBJ ( aafi , OpGroup , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * InputSegment = NULL ;
aafObject * InputSegments = aaf_get_propertyValue ( OpGroup , PID_OperationGroup_InputSegments , & AAFTypeID_SegmentStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint32_t i = 0 ;
AAFI_foreach_ObjectInSet ( & InputSegment , InputSegments , i , __td )
{
parse_Segment ( aafi , InputSegment , & __td ) ;
aafi - > ctx . current_combined_clip_channel_num + + ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafi_dump_obj ( aafi , NULL , & __td , 0 , NULL , - 1 , " " ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiAudioTrack * current_track = aafi - > ctx . current_track ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiTrackFormat_e track_format = AAFI_TRACK_FORMAT_UNKNOWN ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
current_track - > format = track_format ;
RESET_CTX__AudioChannelCombiner ( aafi - > ctx ) ;
} else if ( aafUIDCmp ( OperationIdentification , & AAFOperationDef_MonoAudioGain ) ) {
aafObject * Param = NULL ;
aafObject * Parameters = aaf_get_propertyValue ( OpGroup , PID_OperationGroup_Parameters , & AAFTypeID_ParameterStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 */
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , OpGroup , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint32_t i = 0 ;
AAFI_foreach_ObjectInSet ( & Param , Parameters , i , __td )
{
parse_Parameter ( aafi , Param , & __td ) ;
}
} else if ( aafUIDCmp ( OperationIdentification , & AAFOperationDef_MonoAudioPan ) ) {
/* TODO Should Only be Track-based (first Segment of TimelineMobSlot.) */
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * Param = NULL ;
aafObject * Parameters = aaf_get_propertyValue ( OpGroup , PID_OperationGroup_Parameters , & AAFTypeID_ParameterStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 */
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , OpGroup , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ) ;
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
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 */
}
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , OpGroup , & __td ) ;
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
uint32_t i = 0 ;
AAFI_foreach_ObjectInSet ( & Param , Parameters , i , __td )
{
parse_Parameter ( aafi , Param , & __td ) ;
}
} else {
/*
* 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 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * Param = NULL ;
aafObject * Parameters = aaf_get_propertyValue ( OpGroup , PID_OperationGroup_Parameters , & AAFTypeID_ParameterStrongReferenceVector ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 */
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint32_t i = 0 ;
AAFI_foreach_ObjectInSet ( & Param , Parameters , i , __td )
{
parse_Parameter ( aafi , Param , & __td ) ;
2023-11-13 14:11:35 -05:00
}
}
2024-03-10 16:55:40 -04:00
end :
2023-11-13 14:11:35 -05:00
/*
2024-03-10 16:55:40 -04:00
* 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 .
2023-11-13 14:11:35 -05:00
*/
2024-03-10 16:55:40 -04:00
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 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint32_t i = 0 ;
AAFI_foreach_ObjectInSet ( & InputSegment , InputSegments , i , __td )
{
parse_Segment ( aafi , InputSegment , & __td ) ;
}
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
/* End of current OperationGroup context. */
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * Obj = OpGroup ;
for ( ; Obj ! = NULL & & aafUIDCmp ( Obj - > Class - > ID , & AAFClassID_ContentStorage ) = = 0 ; Obj = Obj - > Parent )
if ( ! aafUIDCmp ( Obj - > Class - > ID , & AAFClassID_OperationGroup ) )
break ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( aafUIDCmp ( OperationIdentification , & AAFOperationDef_MonoAudioGain ) ) {
if ( ! aafUIDCmp ( Obj - > Class - > ID , & AAFClassID_TimelineMobSlot ) ) {
if ( aafi - > ctx . current_clip_gain_is_used = = 0 ) {
aafi_freeAudioGain ( aafi - > ctx . current_clip_gain ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( aafi - > ctx . current_clip_variable_gain_is_used = = 0 ) {
aafi_freeAudioGain ( aafi - > ctx . current_clip_variable_gain ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
RESET_CTX__AudioGain ( aafi - > ctx ) ;
}
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return rc ;
2023-11-13 14:11:35 -05:00
}
/*
* Parameter ( abs )
* |
* , - - - - - - - - - - - - - - .
* | |
* ConstantValue VaryingValue
*
*
* A Parameter object shall be owned by an OperationGroup object .
*/
static int
parse_Parameter ( AAF_Iface * aafi , aafObject * Parameter , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 0 ) ;
if ( aafUIDCmp ( Parameter - > Class - > ID , & AAFClassID_ConstantValue ) ) {
return parse_ConstantValue ( aafi , Parameter , & __td ) ;
} else if ( aafUIDCmp ( Parameter - > Class - > ID , & AAFClassID_VaryingValue ) ) {
return parse_VaryingValue ( aafi , Parameter , & __td ) ;
2024-02-14 18:49:10 -05:00
} else {
__td_set ( __td , __ptd , 1 ) ;
2024-03-10 16:55:40 -04:00
TRACE_OBJ_ERROR ( aafi , Parameter , & __td , " Parameter is neither of class Constant nor Varying : %s " , aaft_ClassIDToText ( aafi - > aafd , Parameter - > Class - > ID ) ) ;
2023-11-13 14:11:35 -05:00
}
return - 1 ;
}
static int
parse_ConstantValue ( AAF_Iface * aafi , aafObject * ConstantValue , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
if ( ! aaf_get_propertyValue ( ConstantValue - > Parent , PID_OperationGroup_InputSegments , & AAFTypeID_SegmentStrongReferenceVector ) ) {
__td . eob = 1 ;
}
aafUID_t * ParamDef = aaf_get_propertyValue ( ConstantValue , PID_Parameter_Definition , & AAFTypeID_AUID ) ;
2024-03-10 16:55:40 -04:00
if ( ! ParamDef ) {
TRACE_OBJ_ERROR ( aafi , ConstantValue , & __td , " Missing Parameter::Definition " ) ;
2023-11-13 14:11:35 -05:00
return - 1 ;
}
2024-03-10 16:55:40 -04:00
aafWeakRef_t * OperationDefWeakRef = aaf_get_propertyValue ( ConstantValue - > Parent , PID_OperationGroup_Operation , & AAFTypeID_OperationDefinitionWeakReference ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! OperationDefWeakRef ) {
TRACE_OBJ_ERROR ( aafi , ConstantValue , & __td , " Missing OperationGroup::Operation " ) ;
2023-11-13 14:11:35 -05:00
return - 1 ;
}
2024-03-10 16:55:40 -04:00
aafUID_t * OperationIdentification = aaf_get_OperationIdentificationByWeakRef ( aafi - > aafd , OperationDefWeakRef ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! OperationIdentification ) {
TRACE_OBJ_ERROR ( aafi , ConstantValue , & __td , " Could not retrieve OperationIdentification from parent " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafIndirect_t * Indirect = aaf_get_propertyValue ( ConstantValue , PID_ConstantValue_Value , & AAFTypeID_Indirect ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! Indirect ) {
TRACE_OBJ_ERROR ( aafi , ConstantValue , & __td , " Missing ConstantValue::Value " ) ;
return - 1 ;
}
aafObject * ParentMob = aaf_get_ObjectAncestor ( ConstantValue , & AAFClassID_Mob ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafUID_t * mobUsageCode = aaf_get_propertyValue ( ParentMob , PID_Mob_UsageCode , & AAFTypeID_UsageType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( aafUIDCmp ( OperationIdentification , & AAFOperationDef_MonoAudioGain ) & &
aafUIDCmp ( ParamDef , & AAFParameterDef_Amplitude ) ) {
aafRational_t * value = aaf_get_indirectValue ( aafi - > aafd , Indirect , & AAFTypeID_Rational ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! value ) {
TRACE_OBJ_ERROR ( aafi , ConstantValue , & __td , " Could not retrieve Indirect value for ConstantValue::Value " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiAudioGain * Gain = aafi_newAudioGain ( aafi , AAFI_AUDIO_GAIN_CONSTANT , 0 , value ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! Gain ) {
TRACE_OBJ_ERROR ( aafi , ConstantValue , & __td , " Could not create new gain " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ) ;
}
2023-11-13 14:11:35 -05:00
} else {
2024-03-10 16:55:40 -04:00
/*
* Clip - based Gain
* Gain is saved in context and it will be set to all OperationGroup descendent clips .
*/
2023-11-13 14:11:35 -05:00
if ( aafi - > ctx . current_clip_gain ) {
2024-03-10 16:55:40 -04:00
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 ] ) ) ) ;
2023-11-13 14:11:35 -05:00
aafi_freeAudioGain ( Gain ) ;
return - 1 ;
} else {
aafi - > ctx . current_clip_gain = Gain ;
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , ConstantValue , & __td ) ;
2023-11-13 14:11:35 -05:00
}
}
} else if ( aafUIDCmp ( OperationIdentification , & AAFOperationDef_MonoAudioPan ) & &
aafUIDCmp ( ParamDef , & AAFParameterDef_Pan ) ) {
2024-03-10 16:55:40 -04:00
aafRational_t * value = aaf_get_indirectValue ( aafi - > aafd , Indirect , & AAFTypeID_Rational ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! value ) {
TRACE_OBJ_ERROR ( aafi , ConstantValue , & __td , " Could not retrieve Indirect value for ConstantValue::Value " ) ;
2023-11-13 14:11:35 -05:00
return - 1 ;
}
2024-03-10 16:55:40 -04:00
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 " ) ;
2023-11-13 14:11:35 -05:00
return - 1 ;
}
2024-03-10 16:55:40 -04:00
if ( ! aafi - > ctx . current_track ) {
TRACE_OBJ_ERROR ( aafi , ConstantValue , & __td , " Current track not set " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiAudioPan * Pan = aafi_newAudioPan ( aafi , AAFI_AUDIO_GAIN_CONSTANT , 0 , value ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! Pan ) {
TRACE_OBJ_ERROR ( aafi , ConstantValue , & __td , " Could not create new pan " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
aafi - > ctx . current_track - > pan = Pan ;
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , ConstantValue , & __td ) ;
2023-11-13 14:11:35 -05:00
} else {
2024-03-10 16:55:40 -04:00
TRACE_OBJ_NO_SUPPORT ( aafi , ConstantValue , & __td ) ;
2023-11-13 14:11:35 -05:00
}
return 0 ;
}
static int
parse_VaryingValue ( AAF_Iface * aafi , aafObject * VaryingValue , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
if ( ! aaf_get_propertyValue ( VaryingValue - > Parent , PID_OperationGroup_InputSegments , & AAFTypeID_SegmentStrongReferenceVector ) ) {
__td . eob = 1 ;
}
aafUID_t * ParamDef = aaf_get_propertyValue ( VaryingValue , PID_Parameter_Definition , & AAFTypeID_AUID ) ;
2024-03-10 16:55:40 -04:00
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 " ) ;
2023-11-13 14:11:35 -05:00
return - 1 ;
}
2024-03-10 16:55:40 -04:00
aafUID_t * OperationIdentification = aaf_get_OperationIdentificationByWeakRef ( aafi - > aafd , OperationDefWeakRef ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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. " ) ;
2023-11-13 14:11:35 -05:00
return - 1 ;
}
aafiInterpolation_e interpolation = 0 ;
2024-03-10 16:55:40 -04:00
aafUID_t * InterpolationIdentification = aaf_get_InterpolationIdentificationByWeakRef ( aafi - > aafd , InterpolationDefWeakRef ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! InterpolationIdentification ) {
TRACE_OBJ_WARNING ( aafi , VaryingValue , & __td , " Could not retrieve InterpolationIdentification: Falling back to Linear " ) ;
2023-11-13 14:11:35 -05:00
interpolation = AAFI_INTERPOL_LINEAR ;
} else if ( aafUIDCmp ( InterpolationIdentification , & AAFInterpolationDef_None ) ) {
interpolation = AAFI_INTERPOL_NONE ;
} else if ( aafUIDCmp ( InterpolationIdentification , & AAFInterpolationDef_Linear ) ) {
interpolation = AAFI_INTERPOL_LINEAR ;
} else if ( aafUIDCmp ( InterpolationIdentification , & AAFInterpolationDef_Power ) ) {
interpolation = AAFI_INTERPOL_POWER ;
} else if ( aafUIDCmp ( InterpolationIdentification , & AAFInterpolationDef_Constant ) ) {
interpolation = AAFI_INTERPOL_CONSTANT ;
} else if ( aafUIDCmp ( InterpolationIdentification , & AAFInterpolationDef_BSpline ) ) {
interpolation = AAFI_INTERPOL_BSPLINE ;
} else if ( aafUIDCmp ( InterpolationIdentification , & AAFInterpolationDef_Log ) ) {
interpolation = AAFI_INTERPOL_LOG ;
} else {
2024-03-10 16:55:40 -04:00
TRACE_OBJ_WARNING ( aafi , VaryingValue , & __td , " Unknown InterpolationIdentification value: Falling back to Linear " ) ;
2023-11-13 14:11:35 -05:00
interpolation = AAFI_INTERPOL_LINEAR ;
}
aafObject * Points = aaf_get_propertyValue ( VaryingValue , PID_VaryingValue_PointList , & AAFTypeID_ControlPointStrongReferenceVector ) ;
2024-03-10 16:55:40 -04:00
if ( ! Points ) {
2023-11-13 14:11:35 -05:00
/*
2024-03-10 16:55:40 -04:00
* Some AAF files from ProTools and LogicPro break standard by having no
2023-11-13 14:11:35 -05:00
* PointList entry for AAFOperationDef_MonoAudioGain .
*/
2024-03-10 16:55:40 -04:00
TRACE_OBJ_WARNING ( aafi , VaryingValue , & __td , " Missing VaryingValue::PointList " ) ;
2023-11-13 14:11:35 -05:00
return - 1 ;
}
if ( aafUIDCmp ( OperationIdentification , & AAFOperationDef_MonoAudioDissolve ) & &
aafUIDCmp ( ParamDef , & AAFParameterDef_Level ) ) {
aafiTransition * Trans = aafi - > ctx . current_transition ;
2024-03-10 16:55:40 -04:00
if ( ! Trans ) {
TRACE_OBJ_ERROR ( aafi , VaryingValue , & __td , " Context current_transition not set " ) ;
2023-11-13 14:11:35 -05:00
return - 1 ;
}
2024-03-10 16:55:40 -04:00
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 ) »
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , VaryingValue , & __td ) ;
2023-11-13 14:11:35 -05:00
} else if ( aafUIDCmp ( OperationIdentification , & AAFOperationDef_MonoAudioGain ) & &
2024-03-10 16:55:40 -04:00
( aafUIDCmp ( ParamDef , & AAFParameterDef_Amplitude ) | | aafUIDCmp ( ParamDef , aaf_get_ParamDefIDByName ( aafi - > aafd , " AvidControlClipRatio " ) ) ) ) {
aafiAudioGain * Gain = aafi_newAudioGain ( aafi , 0 , interpolation , NULL ) ;
if ( ! Gain ) {
TRACE_OBJ_ERROR ( aafi , VaryingValue , & __td , " Could not create new gain " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
int pts_cnt = retrieve_ControlPoints ( aafi , Points , & Gain - > time , & Gain - > value ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( pts_cnt < 0 ) {
TRACE_OBJ_ERROR ( aafi , VaryingValue , & __td , " Could not retrieve ControlPoints " ) ;
2023-11-13 14:11:35 -05:00
free ( Gain ) ;
return - 1 ;
}
2024-03-10 16:55:40 -04:00
Gain - > pts_cnt = ( unsigned int ) pts_cnt ;
2023-11-13 14:11:35 -05:00
// 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 );
// }
2024-03-10 16:55:40 -04:00
/*
* 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 .
*/
2023-11-13 14:11:35 -05:00
if ( Gain - > pts_cnt = = 2 & &
( Gain - > value [ 0 ] . numerator = = Gain - > value [ 1 ] . numerator ) & &
( Gain - > value [ 0 ] . denominator = = Gain - > value [ 1 ] . denominator ) ) {
2024-03-10 16:55:40 -04:00
if ( aafRationalToDouble ( Gain - > value [ 0 ] ) = = 1.0f ) {
2023-11-13 14:11:35 -05:00
/*
2024-03-10 16:55:40 -04:00
* Skipping any 1 : 1 gain allows not to miss any other actual gain ( eg . DR_Audio_Levels . aaf , Resolve 18.5 . AAF )
2024-02-14 18:49:10 -05:00
*
│ 02412 │ │ ├ ─ ─ ◻ AAFClassID_OperationGroup ( OpIdent : AAFOperationDef_MonoAudioGain ; Length : 284630 )
err │ 03 839 │ │ │ ├ ─ ─ ◻ AAFClassID_VaryingValue : : Value is continuous 1 : 1 ( 0 db ) , skipping it .
│ │ │ │ │
│ 02412 │ │ │ └ ─ ─ ◻ AAFClassID_OperationGroup ( OpIdent : AAFOperationDef_MonoAudioGain ; Length : 284630 )
│ 03660 │ │ │ ├ ─ ─ ◻ AAFClassID_ConstantValue ( Value : 6023 / 536870912 - 99.0 dB )
│ 02 983 │ │ │ └ ─ ─ ◻ AAFClassID_SourceClip ( Length : 284630 )
│ 02 988 │ │ │ └ ─ ─ ◻ AAFClassID_MasterMob ( UsageCode : n / a ) : speech - sample . mp3 - - 100 db
│ 04553 │ │ │ └ ─ ─ ◻ AAFClassID_TimelineMobSlot [ slot : 1 track : 1 ] ( DataDef : AAFDataDef_Sound )
│ 031 93 │ │ │ └ ─ ─ ◻ AAFClassID_SourceClip ( Length : 284630 )
│ 042 97 │ │ │ └ ─ ─ ◻ AAFClassID_SourceMob ( UsageCode : n / a ) : speech - sample . mp3 - - 100 db
│ 01342 │ │ │ └ ─ ─ ◻ AAFClassID_PCMDescriptor
│ 0152 9 │ │ │ └ ─ ─ ◻ AAFClassID_NetworkLocator : file : ///C:/Users/user/Desktop/libAAF/test/res/speech-sample.mp3
2023-11-13 14:11:35 -05:00
*/
2024-03-10 16:55:40 -04:00
TRACE_OBJ_INFO ( aafi , VaryingValue , & __td , " Value is continuous 1:1 (0db), skipping it. " ) ;
2023-11-13 14:11:35 -05:00
aafi_freeAudioGain ( Gain ) ;
return - 1 ;
}
Gain - > flags | = AAFI_AUDIO_GAIN_CONSTANT ;
} else {
Gain - > flags | = AAFI_AUDIO_GAIN_VARIABLE ;
}
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
if ( aafi - > ctx . current_track - > gain ) {
2024-03-10 16:55:40 -04:00
TRACE_OBJ_ERROR ( aafi , VaryingValue , & __td , " Track volume was already set " ) ;
2023-11-13 14:11:35 -05:00
aafi_freeAudioGain ( Gain ) ;
return - 1 ;
} else {
aafi - > ctx . current_track - > gain = Gain ;
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , VaryingValue , & __td ) ;
2023-11-13 14:11:35 -05:00
}
} else {
2024-03-10 16:55:40 -04:00
/*
* Clip - based Gain
* Gain is saved in context and it will be set to all OperationGroup descendent clips .
*/
2023-11-13 14:11:35 -05:00
if ( Gain - > flags & AAFI_AUDIO_GAIN_CONSTANT ) {
if ( aafi - > ctx . current_clip_gain ) {
2024-03-10 16:55:40 -04:00
TRACE_OBJ_ERROR ( aafi , VaryingValue , & __td , " Clip gain was already set " ) ;
2023-11-13 14:11:35 -05:00
aafi_freeAudioGain ( Gain ) ;
return - 1 ;
} else {
aafi - > ctx . current_clip_gain = Gain ;
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , VaryingValue , & __td ) ;
2023-11-13 14:11:35 -05:00
}
} else {
2024-03-10 16:55:40 -04:00
if ( aafi - > ctx . current_clip_variable_gain ) {
TRACE_OBJ_ERROR ( aafi , VaryingValue , & __td , " Clip automation was already set " ) ;
2023-11-13 14:11:35 -05:00
aafi_freeAudioGain ( Gain ) ;
return - 1 ;
} else {
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_clip_variable_gain = Gain ;
TRACE_OBJ ( aafi , VaryingValue , & __td ) ;
2023-11-13 14:11:35 -05:00
}
}
}
} else if ( aafUIDCmp ( OperationIdentification , & AAFOperationDef_MonoAudioPan ) & &
aafUIDCmp ( ParamDef , & AAFParameterDef_Pan ) ) {
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiAudioPan * Pan = aafi_newAudioPan ( aafi , 0 , interpolation , NULL ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! Pan ) {
TRACE_OBJ_ERROR ( aafi , VaryingValue , & __td , " Could not create new pan " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
int pts_cnt = retrieve_ControlPoints ( aafi , Points , & Pan - > time , & Pan - > value ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( pts_cnt < 0 ) {
TRACE_OBJ_ERROR ( aafi , VaryingValue , & __td , " Could not retrieve ControlPoints " ) ;
2023-11-13 14:11:35 -05:00
free ( Pan ) ;
return - 1 ;
}
2024-03-10 16:55:40 -04:00
Pan - > pts_cnt = ( unsigned int ) pts_cnt ;
2023-11-13 14:11:35 -05:00
// 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 );
// }
2024-03-10 16:55:40 -04:00
/*
* 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 .
*/
2023-11-13 14:11:35 -05:00
if ( Pan - > pts_cnt = = 2 & &
( Pan - > value [ 0 ] . numerator = = Pan - > value [ 1 ] . numerator ) & &
( Pan - > value [ 0 ] . denominator = = Pan - > value [ 1 ] . denominator ) ) {
Pan - > flags | = AAFI_AUDIO_GAIN_CONSTANT ;
} else {
Pan - > flags | = AAFI_AUDIO_GAIN_VARIABLE ;
}
2024-03-10 16:55:40 -04:00
aafi - > ctx . current_track - > pan = Pan ;
TRACE_OBJ ( aafi , VaryingValue , & __td ) ;
2023-11-13 14:11:35 -05:00
} else {
2024-03-10 16:55:40 -04:00
TRACE_OBJ_NO_SUPPORT ( aafi , VaryingValue , & __td ) ;
2023-11-13 14:11:35 -05:00
}
return 0 ;
}
2024-03-10 16:55:40 -04:00
/* ****************************************************************************
* 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
*/
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
parse_EssenceDescriptor ( AAF_Iface * aafi , aafObject * EssenceDesc , td * __ptd )
2023-11-13 14:11:35 -05:00
{
2024-03-10 16:55:40 -04:00
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! aaf_get_property ( EssenceDesc , PID_EssenceDescriptor_Locator ) )
__td . eob = 1 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ) ) {
/*
* 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 / 2997f ps - DFTC . aaf
*/
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 ) ;
}
/*
* 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 .
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * Locator = NULL ;
aafObject * Locators = aaf_get_propertyValue ( EssenceDesc , PID_EssenceDescriptor_Locator , & AAFTypeID_LocatorStrongReferenceVector ) ;
uint32_t i = 0 ;
AAFI_foreach_ObjectInSet ( & Locator , Locators , i , __td )
2023-11-13 14:11:35 -05:00
{
2024-03-10 16:55:40 -04:00
/* TODO retrieve all locators, then when searching file, try all parsed locators. */
parse_Locator ( aafi , Locator , & __td ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
static int
parse_PCMDescriptor ( AAF_Iface * aafi , aafObject * PCMDescriptor , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 0 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiAudioEssenceFile * audioEssenceFile = ( aafiAudioEssenceFile * ) aafi - > ctx . current_audio_essence ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! audioEssenceFile ) {
TRACE_OBJ_ERROR ( aafi , PCMDescriptor , & __td , " aafi->ctx.current_audio_essence not set " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
audioEssenceFile - > type = AAFI_ESSENCE_TYPE_PCM ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/* Duration of the essence in sample units (not edit units !) */
aafPosition_t * length = aaf_get_propertyValue ( PCMDescriptor , PID_FileDescriptor_Length , & AAFTypeID_PositionType ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! length ) {
TRACE_OBJ_ERROR ( aafi , PCMDescriptor , & __td , " Missing FileDescriptor::Length " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
audioEssenceFile - > length = * length ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
uint32_t * channels = aaf_get_propertyValue ( PCMDescriptor , PID_SoundDescriptor_Channels , & AAFTypeID_UInt32 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! channels ) {
TRACE_OBJ_ERROR ( aafi , PCMDescriptor , & __td , " Missing SoundDescriptor::Channels " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( * channels > = USHRT_MAX ) {
TRACE_OBJ_ERROR ( aafi , PCMDescriptor , & __td , " SoundDescriptor::Channels bigger than USHRT_MAX " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
audioEssenceFile - > channels = * ( uint16_t * ) channels ;
aafRational_t * samplerate = aaf_get_propertyValue ( PCMDescriptor , PID_FileDescriptor_SampleRate , & AAFTypeID_Rational ) ;
if ( ! samplerate ) {
TRACE_OBJ_ERROR ( aafi , PCMDescriptor , & __td , " Missing FileDescriptor::SampleRate " ) ;
return - 1 ;
}
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 ;
}
audioEssenceFile - > samplerate = ( uint32_t ) samplerate - > numerator ;
audioEssenceFile - > samplerateRational - > numerator = samplerate - > numerator ;
audioEssenceFile - > samplerateRational - > denominator = samplerate - > denominator ;
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 ;
}
if ( * samplesize > = USHRT_MAX ) {
TRACE_OBJ_ERROR ( aafi , PCMDescriptor , & __td , " SoundDescriptor::QuantizationBits bigger than USHRT_MAX : %u " , samplesize ) ;
return - 1 ;
}
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 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiAudioEssenceFile * audioEssenceFile = ( aafiAudioEssenceFile * ) aafi - > ctx . current_audio_essence ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! audioEssenceFile ) {
TRACE_OBJ_ERROR ( aafi , WAVEDescriptor , & __td , " aafi->ctx.current_audio_essence not set " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
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 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
audioEssenceFile - > summary = summary ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* 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
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , WAVEDescriptor , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
}
2023-11-13 14:11:35 -05:00
static int
2024-03-10 16:55:40 -04:00
parse_AIFCDescriptor ( AAF_Iface * aafi , aafObject * AIFCDescriptor , td * __ptd )
2023-11-13 14:11:35 -05:00
{
2024-03-10 16:55:40 -04:00
struct trace_dump __td ;
__td_set ( __td , __ptd , 0 ) ;
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
aafiAudioEssenceFile * audioEssenceFile = ( aafiAudioEssenceFile * ) aafi - > ctx . current_audio_essence ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! audioEssenceFile ) {
TRACE_OBJ_ERROR ( aafi , AIFCDescriptor , & __td , " aafi->ctx.current_audio_essence not set " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
audioEssenceFile - > type = AAFI_ESSENCE_TYPE_AIFC ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafProperty * summary = aaf_get_property ( AIFCDescriptor , PID_AIFCDescriptor_Summary ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! summary ) {
TRACE_OBJ_ERROR ( aafi , AIFCDescriptor , & __td , " Missing AIFCDescriptor::Summary " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
audioEssenceFile - > summary = summary ;
2023-11-13 14:11:35 -05:00
/*
2024-03-10 16:55:40 -04:00
* 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 .
2023-11-13 14:11:35 -05:00
*/
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , AIFCDescriptor , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 videoEssenceFile */
aafiVideoEssence * videoEssenceFile = aafi - > ctx . current_video_essence ;
if ( ! videoEssenceFile ) {
TRACE_OBJ_ERROR ( aafi , DIDescriptor , & __td , " aafi->ctx.current_video_essence not set " ) ;
return - 1 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
/*
* « 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 . »
*/
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
aafRational_t * framerate = aaf_get_propertyValue ( DIDescriptor , PID_FileDescriptor_SampleRate , & AAFTypeID_Rational ) ;
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
if ( ! framerate ) {
TRACE_OBJ_ERROR ( aafi , DIDescriptor , & __td , " Missing FileDescriptor::SampleRate (framerate) " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
videoEssenceFile - > 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 ?
*/
return 0 ;
2023-11-13 14:11:35 -05:00
}
static int
2024-03-10 16:55:40 -04:00
parse_CDCIDescriptor ( AAF_Iface * aafi , aafObject * CDCIDescriptor , td * __ptd )
2023-11-13 14:11:35 -05:00
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 0 ) ;
2024-03-10 16:55:40 -04:00
/* TODO parse CDCI class */
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
int rc = parse_DigitalImageDescriptor ( aafi , CDCIDescriptor , __ptd ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! rc )
TRACE_OBJ ( aafi , CDCIDescriptor , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return rc ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* Locator ( abs )
* |
* , - - - - - - - - - - - - - - - .
* | |
* NetworkLocator TextLocator
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
static int
parse_Locator ( AAF_Iface * aafi , aafObject * Locator , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
__td . eob = 1 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 .
*
* Not encountered yet .
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ_NO_SUPPORT ( aafi , Locator , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ) ;
2023-11-13 14:11:35 -05:00
}
return 0 ;
}
static int
2024-03-10 16:55:40 -04:00
parse_NetworkLocator ( AAF_Iface * aafi , aafObject * NetworkLocator , td * __ptd )
2023-11-13 14:11:35 -05:00
{
struct trace_dump __td ;
2024-03-10 16:55:40 -04:00
__td_set ( __td , __ptd , 0 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
/*
* 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 .
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
char * original_file_path = aaf_get_propertyValue ( NetworkLocator , PID_NetworkLocator_URLString , & AAFTypeID_String ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( original_file_path = = NULL ) {
TRACE_OBJ_ERROR ( aafi , NetworkLocator , & __td , " Missing NetworkLocator::URLString " ) ;
goto err ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
} 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 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
} else {
TRACE_OBJ_ERROR ( aafi , NetworkLocator , & __td , " No current essence set " ) ;
goto err ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , NetworkLocator , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
err :
free ( original_file_path ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
static int
parse_EssenceData ( AAF_Iface * aafi , aafObject * EssenceData , td * __ptd )
{
struct trace_dump __td ;
__td_set ( __td , __ptd , 1 ) ;
__td . eob = 1 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
int rc = 0 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
char * streamName = NULL ;
char * dataPath = NULL ;
aafiAudioEssenceFile * audioEssenceFile = ( aafiAudioEssenceFile * ) aafi - > ctx . current_audio_essence ;
if ( ! audioEssenceFile ) {
TRACE_OBJ_ERROR ( aafi , EssenceData , & __td , " aafi->ctx.current_audio_essence not set " ) ;
2023-11-13 14:11:35 -05:00
return - 1 ;
}
2024-03-10 16:55:40 -04:00
streamName = aaf_get_propertyValue ( EssenceData , PID_EssenceData_Data , & AAFTypeID_String ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! streamName ) {
TRACE_OBJ_ERROR ( aafi , EssenceData , & __td , " Missing EssenceData::Data " ) ;
goto err ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
char * path = aaf_get_ObjectPath ( EssenceData ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! path ) {
TRACE_OBJ_ERROR ( aafi , EssenceData , & __td , " Could not retrieve EssenceData node path " ) ;
goto err ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
cfbNode * DataNode = cfb_getNodeByPath ( aafi - > aafd - > cfbd , dataPath , 0 ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! DataNode ) {
TRACE_OBJ_ERROR ( aafi , EssenceData , & __td , " Could not retrieve Data stream node: %s " , dataPath ) ;
goto err ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
TRACE_OBJ ( aafi , EssenceData , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
debug ( " Embedded data stream : %s " , dataPath ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
audioEssenceFile - > node = DataNode ;
audioEssenceFile - > is_embedded = 1 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
rc = 0 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
goto end ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
err :
rc = - 1 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
end :
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
free ( streamName ) ;
free ( dataPath ) ;
return rc ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
static int
retrieve_UserComments ( AAF_Iface * aafi , aafObject * UserComments , aafiMetaData * * metadataList )
{
aafObject * UserComment = NULL ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
int error = 0 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
AAF_foreach_ObjectInSet ( & UserComment , UserComments , NULL )
{
char * text = NULL ;
char * name = NULL ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! aafUIDCmp ( UserComment - > Class - > ID , & AAFClassID_TaggedValue ) ) {
warning ( " Parsing UserComments: Expected TaggedValue but got %s " , aaft_ClassIDToText ( aafi - > aafd , UserComment - > Class - > ID ) ) ;
goto UserCommentError ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
name = aaf_get_propertyValue ( UserComment , PID_TaggedValue_Name , & AAFTypeID_String ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! name ) {
warning ( " Parsing UserComments: Missing TaggedValue::Name " ) ;
goto UserCommentError ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafIndirect_t * Indirect = aaf_get_propertyValue ( UserComment , PID_TaggedValue_Value , & AAFTypeID_Indirect ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! Indirect ) {
warning ( " Parsing UserComments: Missing TaggedValue::Value " ) ;
goto UserCommentError ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
text = aaf_get_indirectValue ( aafi - > aafd , Indirect , & AAFTypeID_String ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! text ) {
warning ( " Parsing UserComments: Could not retrieve Indirect value for TaggedValue::Value " ) ;
goto UserCommentError ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafiMetaData * Comment = aafi_newMetadata ( aafi , metadataList ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! Comment ) {
warning ( " Parsing UserComments: Could not create new UserComment " ) ;
goto UserCommentError ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
Comment - > name = name ;
Comment - > text = text ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
continue ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
UserCommentError :
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
error + + ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
free ( name ) ;
free ( text ) ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( error )
return - 1 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return 0 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 .
*/
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
* times = calloc ( Points - > Header - > _entryCount , sizeof ( aafRational_t ) ) ;
* values = calloc ( Points - > Header - > _entryCount , sizeof ( aafRational_t ) ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! * times | | ! * values ) {
error ( " Out of memory " ) ;
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafObject * Point = NULL ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
unsigned int i = 0 ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
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 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafRational_t * time = aaf_get_propertyValue ( Point , PID_ControlPoint_Time , & AAFTypeID_Rational ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! time ) {
error ( " Missing ControlPoint::Time " ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
free ( * times ) ;
* times = NULL ;
free ( * values ) ;
* values = NULL ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafIndirect_t * Indirect = aaf_get_propertyValue ( Point , PID_ControlPoint_Value , & AAFTypeID_Indirect ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! Indirect ) {
error ( " Missing Indirect ControlPoint::Value " ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
free ( * times ) ;
* times = NULL ;
free ( * values ) ;
* values = NULL ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
return - 1 ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
aafRational_t * value = aaf_get_indirectValue ( aafi - > aafd , Indirect , & AAFTypeID_Rational ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! value ) {
error ( " Could not retrieve Indirect value for ControlPoint::Value " ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
free ( * times ) ;
* times = NULL ;
free ( * values ) ;
* values = NULL ;
2023-11-13 14:11:35 -05:00
return - 1 ;
}
2024-03-10 16:55:40 -04:00
memcpy ( ( * times + i ) , time , sizeof ( aafRational_t ) ) ;
memcpy ( ( * values + i ) , value , sizeof ( aafRational_t ) ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
i + + ;
}
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( Points - > Header - > _entryCount ! = i ) {
warning ( " ControlPoints _entryCount (%i) does not match iteration (%i). " , Points - > Header - > _entryCount , i ) ;
return ( int ) i ;
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
return ( int ) Points - > Header - > _entryCount ;
2023-11-13 14:11:35 -05:00
}
int
aafi_retrieveData ( AAF_Iface * aafi )
{
2024-02-14 18:49:10 -05:00
/* this __td is only here for debug/error, normal trace is printed from parse_Mob() */
static td __td ;
2024-03-10 16:55:40 -04:00
__td . fn = __LINE__ ;
__td . pfn = 0 ;
__td . lv = 0 ;
__td . ll = calloc ( 1024 , sizeof ( int ) ) ;
if ( ! __td . ll ) {
error ( " Out of memory " ) ;
return - 1 ;
}
2024-02-14 18:49:10 -05:00
__td . ll [ 0 ] = 0 ;
2023-11-13 14:11:35 -05:00
2024-02-14 18:49:10 -05:00
int compositionMobParsed = 0 ;
aafObject * Mob = NULL ;
2024-03-10 16:55:40 -04:00
uint32_t i = 0 ;
AAFI_foreach_ObjectInSet ( & Mob , aafi - > aafd - > Mobs , i , __td )
2023-11-13 14:11:35 -05:00
{
2024-02-14 18:49:10 -05:00
if ( aafUIDCmp ( Mob - > Class - > ID , & AAFClassID_MasterMob ) | |
aafUIDCmp ( Mob - > Class - > ID , & AAFClassID_SourceMob ) ) {
2024-03-10 16:55:40 -04:00
// TRACE_OBJ_WARNING( aafi, Mob, &__td, " PRINTS FOR DEBUG ONLY: Will be parsed later" );
2024-02-14 18:49:10 -05:00
continue ;
}
if ( ! aafUIDCmp ( Mob - > Class - > ID , & AAFClassID_CompositionMob ) ) {
/* there should not be anything other than MasterMob, SourceMob or CompositionMob */
2024-03-10 16:55:40 -04:00
TRACE_OBJ_NO_SUPPORT ( aafi , Mob , & __td ) ;
2024-02-14 18:49:10 -05:00
continue ;
}
2023-11-13 14:11:35 -05:00
aafUID_t * UsageCode = aaf_get_propertyValue ( Mob , PID_Mob_UsageCode , & AAFTypeID_UsageType ) ;
2024-03-10 16:55:40 -04:00
if ( ! aafUIDCmp ( UsageCode , & AAFUsage_TopLevel ) & & ( aafUIDCmp ( aafi - > aafd - > Header . OperationalPattern , & AAFOPDef_EditProtocol ) | | UsageCode ) ) {
2023-11-13 14:11:35 -05:00
/*
* 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 .
*/
2024-03-10 16:55:40 -04:00
// TRACE_OBJ_WARNING( aafi, Mob, &__td, " PRINTS FOR DEBUG ONLY: Will be parsed later" );
2024-02-14 18:49:10 -05:00
continue ;
}
2023-11-13 14:11:35 -05:00
2024-02-14 18:49:10 -05:00
if ( compositionMobParsed ) {
2024-03-10 16:55:40 -04:00
TRACE_OBJ_ERROR ( aafi , Mob , & __td , " Multiple top level CompositionMob not supported yet " ) ;
2023-11-13 14:11:35 -05:00
continue ;
}
RESET_CONTEXT ( aafi - > ctx ) ;
2024-03-10 16:55:40 -04:00
__td . fn = __LINE__ ;
__td . pfn = 0 ;
__td . lv = 0 ;
parse_Mob ( aafi , Mob , & __td ) ;
2023-11-13 14:11:35 -05:00
2024-02-14 18:49:10 -05:00
if ( aafUIDCmp ( UsageCode , & AAFUsage_TopLevel ) ) {
compositionMobParsed = 1 ;
}
}
2023-11-13 14:11:35 -05:00
2024-02-14 18:49:10 -05:00
free ( __td . ll ) ;
2023-11-13 14:11:35 -05:00
if ( aafi - > Timecode = = NULL ) {
2024-02-14 18:49:10 -05:00
/* TODO, shouldn't we leave aafi->Timecode as NULL ? */
2023-11-13 14:11:35 -05:00
warning ( " No timecode found in file. Setting to 00:00:00:00 @ 25fps " ) ;
2024-03-10 16:55:40 -04:00
aafiTimecode * tc = calloc ( 1 , sizeof ( aafiTimecode ) ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( ! tc ) {
error ( " Out of memory " ) ;
2023-11-13 14:11:35 -05:00
return - 1 ;
}
tc - > start = 0 ;
tc - > fps = 25 ;
tc - > drop = 0 ;
tc - > edit_rate = & AAFI_DEFAULT_TC_EDIT_RATE ;
aafi - > Timecode = tc ;
}
/* Post processing */
2024-03-10 16:55:40 -04:00
aafiAudioEssenceFile * audioEssenceFile = NULL ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
AAFI_foreachAudioEssenceFile ( aafi , audioEssenceFile )
2023-11-13 14:11:35 -05:00
{
2024-03-10 16:55:40 -04:00
if ( ! audioEssenceFile - > is_embedded ) {
audioEssenceFile - > usable_file_path = aafi_locate_external_essence_file ( aafi , audioEssenceFile - > original_file_path , aafi - > ctx . options . media_location ) ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
if ( audioEssenceFile - > usable_file_path = = NULL ) {
warning ( " Could not locate external audio essence file '%s' " , audioEssenceFile - > original_file_path ) ;
2024-02-14 18:49:10 -05:00
}
2023-11-13 14:11:35 -05:00
}
2024-03-10 16:55:40 -04:00
if ( audioEssenceFile - > summary | | audioEssenceFile - > usable_file_path ) {
aafi_parse_audio_essence ( aafi , audioEssenceFile ) ;
2023-11-13 14:11:35 -05:00
}
}
2024-02-14 18:49:10 -05:00
/*
* Define AAF samplerate and samplesize with the most used values accross all audio essences .
*/
2023-12-26 08:35:14 -05:00
2024-02-14 18:49:10 -05:00
uint32_t maxOccurence = 0 ;
2024-03-10 16:55:40 -04:00
AAFI_foreachAudioEssenceFile ( aafi , audioEssenceFile )
2023-12-26 08:35:14 -05:00
{
2024-03-10 16:55:40 -04:00
uint32_t count = 1 ;
aafiAudioEssenceFile * ae = NULL ;
2024-02-14 18:49:10 -05:00
2024-03-10 16:55:40 -04:00
if ( audioEssenceFile - > samplerate = = aafi - > Audio - > samplerate & &
audioEssenceFile - > samplesize = = aafi - > Audio - > samplesize ) {
2023-12-26 08:35:14 -05:00
continue ;
}
2024-03-10 16:55:40 -04:00
AAFI_foreachEssence ( audioEssenceFile - > next , ae )
2024-02-14 18:49:10 -05:00
{
2024-03-10 16:55:40 -04:00
if ( audioEssenceFile - > samplerate = = ae - > samplerate & & audioEssenceFile - > samplesize = = ae - > samplesize ) {
2024-02-14 18:49:10 -05:00
count + + ;
}
}
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
debug ( " Essence count @ %u Hz / %u bits : %i " , audioEssenceFile - > samplerate , audioEssenceFile - > samplesize , count ) ;
2024-02-14 18:49:10 -05:00
if ( count > maxOccurence ) {
maxOccurence = count ;
2024-03-10 16:55:40 -04:00
aafi - > Audio - > samplesize = audioEssenceFile - > samplesize ;
aafi - > Audio - > samplerate = audioEssenceFile - > samplerate ;
aafi - > Audio - > samplerateRational = audioEssenceFile - > samplerateRational ;
2023-12-26 08:35:14 -05:00
}
2024-02-14 18:49:10 -05:00
}
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
aafiVideoEssence * videoEssenceFile = NULL ;
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
AAFI_foreachVideoEssence ( aafi , videoEssenceFile )
2024-02-14 18:49:10 -05:00
{
2024-03-10 16:55:40 -04:00
if ( videoEssenceFile - > original_file_path = = NULL ) {
2023-12-26 08:35:14 -05:00
continue ;
}
2024-03-10 16:55:40 -04:00
videoEssenceFile - > usable_file_path = aafi_locate_external_essence_file ( aafi , videoEssenceFile - > original_file_path , aafi - > ctx . options . media_location ) ;
2023-12-26 08:35:14 -05:00
2024-03-10 16:55:40 -04:00
if ( videoEssenceFile - > usable_file_path = = NULL ) {
error ( " Could not locate external video essence file '%s' " , videoEssenceFile - > original_file_path ) ;
2023-12-26 08:35:14 -05:00
continue ;
}
}
2024-02-14 18:49:10 -05:00
aafPosition_t trackEnd = 0 ;
2023-11-13 14:11:35 -05:00
aafiAudioTrack * audioTrack = NULL ;
2024-03-10 16:55:40 -04:00
AAFI_foreachAudioTrack ( aafi , audioTrack )
2023-11-13 14:11:35 -05:00
{
2024-02-14 18:49:10 -05:00
if ( aafi - > compositionLength_editRate ) {
2024-03-10 16:55:40 -04:00
trackEnd = aafi_convertUnit ( audioTrack - > current_pos , audioTrack - > edit_rate , aafi - > compositionLength_editRate ) ;
2024-02-14 18:49:10 -05:00
} else {
trackEnd = audioTrack - > current_pos ;
}
if ( trackEnd > aafi - > compositionLength ) {
2024-03-10 16:55:40 -04:00
debug ( " Setting compositionLength with audio track \" %s \" (%u) : % " PRIi64 , audioTrack - > name , audioTrack - > number , audioTrack - > current_pos ) ;
2024-02-14 18:49:10 -05:00
aafi - > compositionLength = audioTrack - > current_pos ;
aafi - > compositionLength_editRate = audioTrack - > edit_rate ;
}
aafiTimelineItem * audioItem = NULL ;
aafiAudioClip * audioClip = NULL ;
2023-11-13 14:11:35 -05:00
2024-03-10 16:55:40 -04:00
AAFI_foreachTrackItem ( audioTrack , audioItem )
2024-02-14 18:49:10 -05:00
{
2024-04-17 17:56:57 -04:00
if ( audioItem - > type ! = AAFI_AUDIO_CLIP ) {
2024-02-14 18:49:10 -05:00
continue ;
}
audioClip = ( aafiAudioClip * ) audioItem - > data ;
audioClip - > channels = aafi_getAudioEssencePointerChannelCount ( audioClip - > essencePointerList ) ;
2024-04-17 17:56:57 -04:00
/*
* we check if any previous clip is using the exact same essence pointer ,
* to avoid duplication and allow to detect when multiple clips are using
* the same essence .
*/
aafiAudioEssencePointer * prev = aafi_audioEssencePointer_exists_before ( aafi , audioClip - > essencePointerList ) ;
if ( prev ) {
audioClip - > essencePointerList = prev ;
}
2023-11-13 14:11:35 -05:00
}
}
aafiVideoTrack * videoTrack = NULL ;
2024-03-10 16:55:40 -04:00
AAFI_foreachVideoTrack ( aafi , videoTrack )
2023-11-13 14:11:35 -05:00
{
2024-02-14 18:49:10 -05:00
if ( aafi - > compositionLength_editRate ) {
2024-03-10 16:55:40 -04:00
trackEnd = aafi_convertUnit ( videoTrack - > current_pos , videoTrack - > edit_rate , aafi - > compositionLength_editRate ) ;
2024-02-14 18:49:10 -05:00
} else {
trackEnd = videoTrack - > current_pos ;
2023-11-13 14:11:35 -05:00
}
2024-02-14 18:49:10 -05:00
if ( trackEnd > aafi - > compositionLength ) {
2024-03-10 16:55:40 -04:00
debug ( " Setting compositionLength with video track \" %s \" (%u) : % " PRIi64 , videoTrack - > name , videoTrack - > number , videoTrack - > current_pos ) ;
2024-02-14 18:49:10 -05:00
aafi - > compositionLength = videoTrack - > current_pos ;
aafi - > compositionLength_editRate = videoTrack - > edit_rate ;
}
2023-11-13 14:11:35 -05:00
}
2024-02-14 18:49:10 -05:00
aafi - > compositionStart = aafi - > Timecode - > start ;
aafi - > compositionStart_editRate = aafi - > Timecode - > edit_rate ;
2023-11-13 14:11:35 -05:00
if ( protools_AAF ( aafi ) ) {
protools_post_processing ( aafi ) ;
}
return 0 ;
}
2024-03-10 16:55:40 -04:00
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 ;
}
2024-03-19 15:59:04 -04:00
laaf_write_log ( aafi - > log , aafi , LOG_SRC_ID_AAF_IFACE , VERB_ERROR , __FILENAME__ , func , line , buf ) ;
2024-03-10 16:55:40 -04:00
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 ) ) ;
}
2024-03-19 15:59:04 -04:00
log - > log_callback ( log , ( void * ) aafi , LOG_SRC_ID_TRACE , 0 , " " , " " , 0 , log - > _msg , log - > user ) ;
2024-03-10 16:55:40 -04:00
/* if end of branch, print one line padding */
if ( Obj & & ( __td - > eob | | state = = TD_ERROR ) )
aafi_dump_obj ( aafi , NULL , __td , 0 , NULL , - 1 , " " ) ;
}
2023-11-13 14:11:35 -05:00
/**
* @ }
*/