ardour/libs/aaf/aaf/AAFCore.h

864 lines
22 KiB
C

/*
* Copyright (C) 2017-2024 Adrien Gesta-Fline
*
* This file is part of libAAF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __AAFCore_h__
#define __AAFCore_h__
/**
* @file AAFCore/AAFCore.h
* @brief Retrieves the AAF Objects Tree from the Compound File Binary.
* @author Adrien Gesta-Fline
* @version 0.1
* @date 04 october 2017
*
* @ingroup AAFCore
* @addtogroup AAFCore
* @brief Retrieves the AAF Objects Tree from the Compound File Binary.
*
* The AAF file structure is based on the Compound File Binary, implemented by LibCFB
* and defined at https://www.amwa.tv/projects/MS-03.shtml
*
* The specifications of the low-level AAF can be found at https://amwa.tv/projects/MS-02.shtml
*
* The specifications of the overall AAF and standard Classes / Properties can be found at
* https://amwa.tv/projects/MS-01.shtml
*
* This is the core of the libAAF library. AAFCore is intendend to :
* - Define the standard AAF classes and properties at run time,
* - retrieve potential custom classes and properties out of the MetaDictionary,
* - retrieve the entire object tree and their properties out of the CFB Tree,
* - provide functions to navigate in the tree and access objects and properties.
*
* Therefore, AAFCore makes a bridge between the low-level Compound File Binary and the
* high level AAFIface, which is used to interpret objects and thus retrieve usable data.
*
* Even though AAFCore can be used as is, it is recommended for complex operations
* like essences and clips retrieval, to use AAFIface.
*
* ### Usage
*
* In order to use libAAF, you should start by allocating AAF_Data with aaf_alloc(), then
* you can load a file by calling aaf_load_file(). aaf_load_file() will not load the entire
* file to memory, but will instead parse the CFB Tree and set AAF_Data accordingly.
*
* @code
* AAF_Data *aafd = aaf_alloc();
* aaf_load_file( aafd, "./path/to/file.aaf" );
* @endcode
*
* Then, you can access the object tree thanks to the access functions, or use the AAFIface
* to extract usable data through a convenient interface.
*
* @code
* // TODO
* @endcode
*
* Once you're done, you can close the file and free the AAF_Data structure by calling
* aaf_release( &aafd );
*
* @code
* aaf_release( &aafd );
* @endcode
*
* @{
*/
#include "aaf/AAFTypes.h"
#include "aaf/LibCFB.h"
/**
* Possible values for aafPropertyDef.isReq.
*/
enum aafPropertyIsRequired_e {
PROP_REQUIRED = 1,
PROP_REQ = 1,
PROP_OPTIONAL = 0,
PROP_OPT = 0
};
/**
* This structure defines a Class property, with a property ID
* and tells if that property is either #REQUIRED or #OPTIONAL.
* This structure is to be added to an aafClass.Properties list
* with the attachNewProperty() macro, and to be pointed to by
* the aafProperty.def field of each parsed property.
*/
typedef struct aafPropertyDefinition {
/**
* Specifies the property ID.
*
* All the standard IDs can be found in AAFDefs/AAFPropertyIDs.h.
*/
uint16_t pid;
/**
* Tells if that property is either #REQUIRED or #OPTIONAL.
*/
aafBoolean_t isReq;
aafBoolean_t meta;
char* name;
/*
* Looks like nobody cares about AAF standard TypeDefinition. All observed files
* had incorrect values for Type's Name and Identification, even Avid's files.
* Thus, PDef->type should NOT be trusted.
*
* TODO: Should be set by attachNewProperty() in AAFClass.c
*/
aafUID_t type;
/**
* Pointer to the next aafPropertyDef in the list.
*/
struct aafPropertyDefinition* next;
} aafPropertyDef;
/**
* Possible values for aafClass.isConcrete.
*/
enum aafClassIsConcrete_e {
ABSTRACT = 0,
ABS = 0,
CONCRETE = 1,
CON = 1
};
/**
* This structure defines an AAF Class.
*
* An AAF Class can be identified thanks to its ClassID.
*
* An AAF Class holds some properties.
*
* An AAF Class can inherit other Classes properties from
* its parents.
*
* An AAF Class can be either a #CONCRETE or an #ABSTRACT
* Class. It is a #CONCRETE Class if it can be directly
* retrieved from the Compound File Nodes Tree as an object.
* Else, it is an #ABSTRACT Class and has to be inherited by
* another Class for its properties to be retrieved.
*/
typedef struct aafclass {
/**
* The ClassID of the Class. When parsing, the ClassID
* correspond to the cfbNode._clsId.
* Note that the CLSID and aafUID_t types are binary
* compatible.
*
* All the standard ClassIDs can be found in AAFDefs/AAFClassDefUIDs.h.
*/
const aafUID_t* ID;
/**
* Tells if the Class is either #CONCRETE or #ABSTRACT.
*
* A Class is #CONCRETE if it can be retrieved as an
* object. Else, a Class is #ABSTRACT if it can't be
* directly retrieved and can only be inherited by
* another Class, so only its members can be retrieved.
*/
aafBoolean_t isConcrete;
/**
* Pointer to a list of aafPropertyDef structs.
*
* These aafPropertyDef define the properties
* owned by the Class.
*/
aafPropertyDef* Properties;
/**
* Pointer to the Parent Class. If this Class has no
* Parent (is root), then the pointer shall be NULL.
*/
struct aafclass* Parent;
aafBoolean_t meta;
/* name is set at runtime */
char* name;
/**
* Pointer to the next Class in the AAF_Data.Class list.
*/
struct aafclass* next;
} aafClass;
/**
* This structure represents a property once it has been parsed.
*
* This structure is to be added to an aafObject.Properties list.
*/
typedef struct aafProperty {
/**
* Specifies the property ID. The pid shall be the same as in the
* #def aafPropertyDef structure.
*
* All the standard IDs can be found in AAFDefs/AAFPropertyIDs.h.
*/
uint16_t pid;
/**
* The _storedForm identifies the “type” of representation chosen
* for this property. This field describes how the property value
* should be interpreted. Note that the stored form described here
* is not the data type of the property value, rather it is the
* type of external representation employed. The data type of a
* given property value is implied by the property ID.
*
* Can take one of the value from #aafStoredForm_e enum.
*/
uint16_t sf;
/**
* Holds a pointer to the corresponding property definition
* aafPropertyDef struct.
*/
aafPropertyDef* def;
/**
* The length, in bytes, of the #val property value.
*/
uint16_t len;
/**
* The actual property value, of #len length.
*/
void* val;
/**
* Pointer to the next property in an aafObject.Properties list.
*/
struct aafProperty* next;
} aafProperty;
/**
* This structure represents an AAF Object, once it has been parsed.
*
* This structure is to be added to the AAF_Data.Objects list.
*
* Each aafObject correspond to a Compound File Tree Node.
*
* Each aafObject property correspond to a property entry in this
* Node/properties stream.
*/
typedef struct aafObject {
/**
* Pointer to the corresponding Class, in the AAF_Data.Class list.
*/
aafClass* Class;
/**
* Pointer to the corresponding Node in the Compound File Tree.
*/
cfbNode* Node;
/**
* UTF-8 name of the Node in the Compound File Tree, set from cfbNode._ab.
*/
char* Name;
/**
* Pointer to an aafProperty list. This list holds the retrieved
* Object properties.
*/
aafProperty* Properties;
/**
* Pointer to an aafStrongRefSetHeader_t struct.
*
* This pointer keeps track of the Index Header, when the
* Object belongs to either a Set or a Vector, else, it shall
* remain NULL.
*
* Here we can use an aafStrongRefSetHeader_t struct to hold
* an aafStrongRefVectorHeader_t, because both structs begin
* with the same bytes, exept the first one is bigger. So in
* case of a Vector, the remaining bytes will simply remain
* NULL.
*/
aafStrongRefSetHeader_t* Header;
/**
* Pointer to an aafStrongRefSetEntry_t struct.
*
* This pointer keeps track of the Index Entry, when the
* Object belongs to either a Set or a Vector, else, it shall
* remain NULL.
*
* Here we can use an aafStrongRefSetEntry_t struct to hold
* an aafStrongRefVectorEntry_t, because both structs begin
* with the same bytes, exept the first one is bigger. So in
* case of a Vector, the remaining bytes will simply remain
* NULL.
*/
aafStrongRefSetEntry_t* Entry;
/**
* Pointer to the Parent Object, that is the upper "Node" in
* the Compound File Tree.
*/
struct aafObject* Parent;
/**
* Pointer to the next Object in Set/Vector
*/
struct aafObject* next;
struct aafObject* prev;
/**
* Pointer to the next Object in the AAF_Data.Objects list.
*/
struct aafObject* nextObj;
/* keeps track of aafd, mostly to access aafd->verb without having to pass aafd to some functions */
struct _aafData* aafd;
} aafObject;
/**
* This structure is the main structure when using LibAAF.
*
* It holds a pointer to the CFB_Data structure for file
* access, a pointer to the AAF Classes list, a pointer to
* the AAF Objects list and a bunch of pointers to some
* key Objects in the AAF Objects Tree called shortcuts.
*
* Those shortcuts allows to quickly retrieve some AAF
* key Objects without the need to parse the tree everytime.
*/
typedef struct _aafData {
/**
* Pointer to the LibCFB CFB_Data structure.
*/
CFB_Data* cfbd;
/**
* Pointer to the AAF Classes list.
*/
aafClass* Classes;
/**
* Pointer to the AAF Object list.
*
* @note This list is intended to keep track of all the allocated Objects, not for
* parsing. For tree access, the AAF_Data.Root pointer should be used.
*/
aafObject* Objects;
struct Header {
aafObject* obj;
int16_t ByteOrder;
aafTimeStamp_t* LastModified;
aafVersionType_t* Version;
uint32_t ObjectModelVersion;
const aafUID_t* OperationalPattern;
// EssenceContainers; TODO AUIDSet_t
// DescriptiveSchemes: TODO AUIDSet_t
} Header;
struct Identification {
aafObject* obj;
char* CompanyName;
char* ProductName;
aafProductVersion_t* ProductVersion;
char* ProductVersionString;
aafUID_t* ProductID;
aafTimeStamp_t* Date;
aafProductVersion_t* ToolkitVersion;
char* Platform;
aafUID_t* GenerationAUID;
} Identification;
/**
* Pointer to the first Root Object, that is to the the top of the Tree.
*/
aafObject* Root;
/**
* (Shortcut) pointer to the Header Object in the Tree.
*/
// aafObject *Header;
/**
* (Shortcut) pointer to the MetaDictionary Object in the Tree.
*/
aafObject* MetaDictionary;
/**
* (Shortcut) pointer to the ClassDefinition Object in the Tree.
*/
aafObject* ClassDefinition;
/**
* (Shortcut) pointer to the TypeDefinition Object in the Tree.
*/
aafObject* TypeDefinition;
/**
* (Shortcut) pointer to the Identification Object in the Tree.
*/
// aafObject *Identification;
/**
* (Shortcut) pointer to the Content Object in the Tree.
*/
aafObject* Content;
/**
* (Shortcut) pointer to the Dictionary Object in the Tree.
*/
aafObject* Dictionary;
/**
* (Shortcut) pointer to the Mobs Object in the Tree.
*/
aafObject* Mobs;
/**
* (Shortcut) pointer to the EssenceData Object in the Tree.
*/
aafObject* EssenceData;
/**
* (Shortcut) pointer to the OperationDefinition Object in the Tree.
*/
aafObject* OperationDefinition;
/**
* (Shortcut) pointer to the ParameterDefinition Object in the Tree.
*/
aafObject* ParameterDefinition;
/**
* (Shortcut) pointer to the DataDefinition Object in the Tree.
*/
aafObject* DataDefinition;
/**
* (Shortcut) pointer to the PluginDefinition Object in the Tree.
*/
aafObject* PluginDefinition;
/**
* (Shortcut) pointer to the CodecDefinition Object in the Tree.
*/
aafObject* CodecDefinition;
/**
* (Shortcut) pointer to the ContainerDefinition Object in the Tree.
*/
aafObject* ContainerDefinition;
/**
* (Shortcut) pointer to the InterpolationDefinition Object in the Tree.
*/
aafObject* InterpolationDefinition;
/**
* (Shortcut) pointer to the KLVDataDefinition Object in the Tree.
*/
aafObject* KLVDataDefinition;
/**
* (Shortcut) pointer to the TaggedValueDefinition Object in the Tree.
*/
aafObject* TaggedValueDefinition;
struct aafLog* log;
} AAF_Data;
/**
* Compares two aafUID_t, returns 1 if equal or 0 otherwise.
* https://github.com/Ardour/ardour/pull/805#issuecomment-1595788696
*/
#define aafUIDCmp(auid1, auid2) \
((auid1) != NULL && \
((auid2)) != NULL && \
(auid1)->Data1 == (auid2)->Data1 && \
(auid1)->Data2 == (auid2)->Data2 && \
(auid1)->Data3 == (auid2)->Data3 && \
(auid1)->Data4[0] == (auid2)->Data4[0] && \
(auid1)->Data4[1] == (auid2)->Data4[1] && \
(auid1)->Data4[2] == (auid2)->Data4[2] && \
(auid1)->Data4[3] == (auid2)->Data4[3] && \
(auid1)->Data4[4] == (auid2)->Data4[4] && \
(auid1)->Data4[5] == (auid2)->Data4[5] && \
(auid1)->Data4[6] == (auid2)->Data4[6] && \
(auid1)->Data4[7] == (auid2)->Data4[7])
/**
* Compares two aafMobID_t, returns 1 if equal or 0 otherwise.
*/
#define aafMobIDCmp(mobID1, mobID2) \
((mobID1) != NULL && (mobID2) != NULL && memcmp ((mobID1), (mobID2), sizeof (aafMobID_t)) == 0)
/**
* Compares two aafSlotID_t, returns 1 if equal or 0 otherwise.
* NOTE: is unused.
*/
#define aafSlotIDCmp(slotID1, slotID2) \
((slotID1) == (slotID2))
/**
* Converts an aafRational_t to a float number.
*/
#define aafRationalToFloat(r) \
(((r).denominator == 0) ? 0 : ((float)(r).numerator / (float)(r).denominator))
#define aafRationalToDouble(r) \
(((r).denominator == 0) ? 0 : ((double)(r).numerator / (r).denominator))
/**
* Converts an aafRational_t to a int64 number.
* NOTE: is unused.
*/
#define aafRationalToint64(r) \
(((r).denominator == 0) ? 0 : (int64_t) ((r).numerator / (r).denominator))
/**
* Loops through each aafPropertyIndexEntry_t of a "properties" node stream.
*
* @param Header Pointer to the stream's aafPropertyIndexHeader_t struct.
* @param Entry Pointer that will receive each aafPropertyIndexEntry_t struct.
* @param Value Pointer to each property's data value, of aafPropertyIndexEntry_t._length
* bytes length.
* @param i uint32_t iterator.
*/
#define foreachPropertyEntry(propStream, Header, Entry, Value, valueOffset, i) \
for (valueOffset = sizeof (aafPropertyIndexHeader_t) + (Header._entryCount * sizeof (aafPropertyIndexEntry_t)), \
i = 0; \
i < Header._entryCount && \
memcpy (&Entry, (propStream + ((sizeof (aafPropertyIndexHeader_t)) + (sizeof (aafPropertyIndexEntry_t) * i))), sizeof (aafPropertyIndexEntry_t)) && \
(Value = propStream + valueOffset); \
valueOffset += Entry._length, \
i++)
/**
* @name Initialisation functions
* @{
*/
/**
* Allocates a new AAF_Data structure.
*
* @return A pointer to the newly allocated structure.
*/
AAF_Data*
aaf_alloc (struct aafLog* log);
/**
* Loads an AAF file and sets the AAF_Data sructure accordingly.
*
* @param aafd Pointer to the AAF_Data structure.
* @param file Pointer to a null terminated string holding the filepath.
*
* @return 0 on success\n
* 1 on failure
*/
int
aaf_load_file (AAF_Data* aafd,
const char* file);
/**
* @}
*/
/**
* @name Release function
* @{
*/
/**
* Releases the CFB_Data structure, fclose() the file and frees the AAF_Data structure.
*
* @param aafd Pointer to the AAF_Data structure.
*/
void
aaf_release (AAF_Data** aafd);
/**
* @}
*/
/**
* @name Access functions
* @{
*/
/**
* Retrieves, for a given Object, its path in the Compound File Binary Tree.
*
* @note It is the caller responsability to free the returned pointer.
*
* @param Obj Pointer to the aafObject.
*
* @return Pointer to a null-terminated string holding the Object's path.
*/
char*
aaf_get_ObjectPath (aafObject* Obj);
/**
* Resolves a given WeakReference from a given Dictionary (a Set or Vector list of
* aafObjects), and returns a pointer to the corresponding Object if it was found.
*
* @param ref Pointer to the WeakReference to search for.
* @param list Pointer to the aafObject list from which the Reference will be searched for.
*
* @return A pointer to the aafObject if found,\n
* NULL otherwise.
*
*/
aafObject*
aaf_get_ObjectByWeakRef (aafObject* list,
aafWeakRef_t* ref);
aafUID_t*
aaf_get_InterpolationIdentificationByWeakRef (AAF_Data* aafd, aafWeakRef_t* InterpolationDefWeakRef);
aafUID_t*
aaf_get_OperationIdentificationByWeakRef (AAF_Data* aafd, aafWeakRef_t* OperationDefWeakRef);
aafUID_t*
aaf_get_ContainerIdentificationByWeakRef (AAF_Data* aafd, aafWeakRef_t* ContainerDefWeakRef);
aafUID_t*
aaf_get_DataIdentificationByWeakRef (AAF_Data* aafd, aafWeakRef_t* DataDefWeakRef);
aafObject*
aaf_get_ObjectAncestor (aafObject* Obj, const aafUID_t* ClassID);
int
aaf_ObjectInheritsClass (aafObject* Obj, const aafUID_t* classID);
/**
* Retrieves a Mob Object by its given MobID.
*
* @param Mobs Pointer to the Mob Object list.
* @param MobID Pointer to the MobID where're looking for.
*
* @return A pointer to the Mob aafObject if found,\n
* NULL otherwise.
*/
aafObject*
aaf_get_MobByID (aafObject* Mobs,
aafMobID_t* MobID);
aafObject*
aaf_get_MobSlotBySlotID (aafObject* MobSlots,
aafSlotID_t SlotID);
aafObject*
aaf_get_EssenceDataByMobID (AAF_Data* aafd, aafMobID_t* MobID);
/**
* Loops through each aafObject of a list, that is of a Set or Vector. It is also
* possible to filter the returned Object by ClassID.
*
* This function should be used as the conditional expression of a while loop. The
* aaf_foreach_ObjectInSet() is an implementation of this.
*
* @param Obj Pointer to pointer to an aafObject structure that will receive each
* Object of the list.
* @param head Pointer to the first Object of the list.
* @param filter Pointer to a ClassID to use as a filter, shall be NULL if unused.
*
* @return 1 if has another Object,\n
* 0 if has no more Object.
*/
int
_aaf_foreach_ObjectInSet (aafObject** Obj,
aafObject* head,
const aafUID_t* filter);
/**
* Convenience macro, that implements the _aaf_foreach_ObjectInSet() function. This should
* be used istead of directly calling _aaf_foreach_ObjectInSet().
*/
#define AAF_foreach_ObjectInSet(Obj, head, filter) \
while (_aaf_foreach_ObjectInSet (Obj, head, filter))
void*
aaf_get_TaggedValueByName (AAF_Data* aafd, aafObject* TaggedValueVector, const char* name, const aafUID_t* type);
/**
* Retrieves an Object property by ID.
*
* @param Obj Pointer to the Object to get the property from.
* @param pid Index of the requested property.
*
* @return A pointer to the property if found,\n
* NULL otherwise.
*/
aafProperty*
aaf_get_property (aafObject* Obj,
aafPID_t pid);
aafUID_t*
aaf_get_ParamDefIDByName (AAF_Data* aafd, const char* name);
/**
* Retrieves a Property ID by its name.
*
* @param aafd Pointer to the AAF_Data structure.
* @param name Name of the property to look for.
*
* @return The PID of the property if it was found\n
* 0 otherwise.
*/
aafPID_t
aaf_get_PropertyIDByName (AAF_Data* aafd,
const char* name);
aafUID_t*
aaf_get_OperationDefIDByName (AAF_Data* aafd, const char* OpDefName);
/**
* Retrieves an Object property by ID, and returns its value.
*
* Special case is the StrongReference, where the function returns
* the Object directly, instead of its reference.
*
* Function performs a type check before it returns.
*
* Caller must free the returned value, only if property is of type
* AAFTypeID_String.
*
* @param Obj Pointer to the Object to get the property from.
* @param pid Index of the requested property.
*
* @return A pointer to the property's value if found,\n
* NULL otherwise.
*/
void*
aaf_get_propertyValue (aafObject* Obj,
aafPID_t pid,
const aafUID_t* typeID);
/**
* Safely get an Indirect value, after it was retrieved using aaf_get_propertyValue().
* Function checks value type and in case of AAFTypeID_String, performs allocation
* and UTF8 conversion.
*
* Caller must free the returned value, only if Indirect is of type
* AAFTypeID_String.
*
* @param aafd Pointer to the AAF_Data structure.
* @param Indirect Pointer to the Indirect structure.
* @param typeDef Type definition expected from the Indirect.
*
* @return A pointer to the Indirect value, or a pointer to an allocated char if Indirect is AAFTypeID_String\n
* NULL in case of error.
*/
void*
aaf_get_indirectValue (AAF_Data* aafd,
aafIndirect_t* Indirect,
const aafUID_t* typeDef);
/**
* @}
*/
/**
* @}
*/
#endif // ! __AAFCore_h__