Update libAAF (upstream v0.6-45-g9171e40)

This commit is contained in:
Robin Gareus 2024-02-15 00:49:10 +01:00
parent 477cff6980
commit a5f4bf39d1
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
13 changed files with 786 additions and 671 deletions

View File

@ -880,43 +880,43 @@ parse_Header (AAF_Data* aafd)
if (ByteOrder == NULL) {
warning ("Missing Header::ByteOrder.");
} else {
aafd->Header.ByteOrder = *ByteOrder;
}
aafd->Header.ByteOrder = *ByteOrder;
aafTimeStamp_t* LastModified = aaf_get_propertyValue (Header, PID_Header_LastModified, &AAFTypeID_TimeStamp);
if (LastModified == NULL) {
warning ("Missing Header::LastModified.");
} else {
aafd->Header.LastModified = LastModified;
}
aafd->Header.LastModified = LastModified;
aafVersionType_t* Version = aaf_get_propertyValue (Header, PID_Header_Version, &AAFTypeID_VersionType);
if (Version == NULL) {
warning ("Missing Header::Version.");
} else {
aafd->Header.Version = Version;
}
aafd->Header.Version = Version;
uint32_t* ObjectModelVersion = aaf_get_propertyValue (Header, PID_Header_ObjectModelVersion, &AAFTypeID_UInt32);
if (ObjectModelVersion == NULL) {
warning ("Missing Header::ObjectModelVersion.");
} else {
aafd->Header.ObjectModelVersion = *ObjectModelVersion;
}
aafd->Header.ObjectModelVersion = *ObjectModelVersion;
const aafUID_t* OperationalPattern = aaf_get_propertyValue (Header, PID_Header_OperationalPattern, &AAFTypeID_AUID);
if (OperationalPattern == NULL) {
warning ("Missing Header::OperationalPattern.");
OperationalPattern = (const aafUID_t*)&AUID_NULL;
aafd->Header.OperationalPattern = (const aafUID_t*)&AUID_NULL;
} else {
aafd->Header.OperationalPattern = OperationalPattern;
}
aafd->Header.OperationalPattern = OperationalPattern;
return 0;
}
@ -934,74 +934,74 @@ parse_Identification (AAF_Data* aafd)
if (Company == NULL) {
warning ("Missing Identification::CompanyName.");
} else {
aafd->Identification.CompanyName = Company;
}
aafd->Identification.CompanyName = Company;
wchar_t* ProductName = aaf_get_propertyValue (Identif, PID_Identification_ProductName, &AAFTypeID_String);
if (ProductName == NULL) {
warning ("Missing Identification::ProductName.");
} else {
aafd->Identification.ProductName = ProductName;
}
aafd->Identification.ProductName = ProductName;
aafProductVersion_t* ProductVersion = aaf_get_propertyValue (Identif, PID_Identification_ProductVersion, &AAFTypeID_ProductVersion);
if (ProductVersion == NULL) {
warning ("Missing Identification::ProductVersion.");
} else {
aafd->Identification.ProductVersion = ProductVersion;
}
aafd->Identification.ProductVersion = ProductVersion;
wchar_t* ProductVersionString = aaf_get_propertyValue (Identif, PID_Identification_ProductVersionString, &AAFTypeID_String);
if (ProductVersionString == NULL) {
warning ("Missing Identification::ProductVersionString.");
} else {
aafd->Identification.ProductVersionString = ProductVersionString;
}
aafd->Identification.ProductVersionString = ProductVersionString;
aafUID_t* ProductID = aaf_get_propertyValue (Identif, PID_Identification_ProductID, &AAFTypeID_AUID);
if (ProductID == NULL) {
warning ("Missing Identification::ProductID.");
} else {
aafd->Identification.ProductID = ProductID;
}
aafd->Identification.ProductID = ProductID;
aafTimeStamp_t* Date = aaf_get_propertyValue (Identif, PID_Identification_Date, &AAFTypeID_TimeStamp);
if (Date == NULL) {
warning ("Missing Identification::Date.");
} else {
aafd->Identification.Date = Date;
}
aafd->Identification.Date = Date;
aafProductVersion_t* ToolkitVersion = aaf_get_propertyValue (Identif, PID_Identification_ToolkitVersion, &AAFTypeID_ProductVersion);
if (ToolkitVersion == NULL) {
warning ("Missing Identification::ToolkitVersion.");
} else {
aafd->Identification.ToolkitVersion = ToolkitVersion;
}
aafd->Identification.ToolkitVersion = ToolkitVersion;
wchar_t* Platform = aaf_get_propertyValue (Identif, PID_Identification_Platform, &AAFTypeID_String);
if (Platform == NULL) {
warning ("Missing Identification::Platform.");
} else {
aafd->Identification.Platform = Platform;
}
aafd->Identification.Platform = Platform;
aafUID_t* GenerationAUID = aaf_get_propertyValue (Identif, PID_Identification_GenerationAUID, &AAFTypeID_AUID);
if (GenerationAUID == NULL) {
warning ("Missing Identification::GenerationAUID.");
} else {
aafd->Identification.GenerationAUID = GenerationAUID;
}
aafd->Identification.GenerationAUID = GenerationAUID;
return 0;
}

View File

@ -69,7 +69,7 @@ embeddedAudioDataReaderCallback (unsigned char* buf, size_t offset, size_t reqLe
static size_t
externalAudioDataReaderCallback (unsigned char* buf, size_t offset, size_t reqLen, void* user1, void* user2, void* user3);
char*
wchar_t*
aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_uri_filepath, const char* search_location)
{
/*
@ -82,10 +82,11 @@ aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_uri_
* uses the / character as the path separator.
*/
char* uri_filepath = NULL;
char* local_filepath = NULL;
char* aaf_path = NULL;
char* retpath = NULL;
char* uri_filepath = NULL;
char* local_filepath = NULL;
char* aaf_path = NULL;
char* foundpath = NULL;
wchar_t* retpath = NULL;
struct uri* uri = NULL;
@ -94,23 +95,14 @@ aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_uri_
goto err;
}
size_t uri_filepath_len = wcslen (original_uri_filepath) + 1;
uri_filepath = malloc (uri_filepath_len);
uri_filepath = laaf_util_wstr2str (original_uri_filepath);
if (uri_filepath == NULL) {
error ("Could not allocate memory : %s", strerror (errno));
error ("Could not convert original_uri_filepath from wstr to str : %ls", original_uri_filepath);
goto err;
}
int reqlen = snprintf (uri_filepath, uri_filepath_len, "%ls", original_uri_filepath);
if (reqlen < 0 || (unsigned)reqlen >= uri_filepath_len) {
error ("Failed converting wide char URI filepath to byte char%s", (reqlen < 0) ? " : encoding error" : "");
goto err;
}
// debug( "Original URI filepath : %s", uri_filepath );
// debug( "Original URI : %s", uri_filepath );
uri = uriParse (uri_filepath, URI_OPT_DECODE_ALL, aafi->dbg);
@ -124,7 +116,7 @@ aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_uri_
goto err;
}
// debug( "Decoded URI's filepath : %s", uri->path );
// debug( "Decoded URI's path : %s", uri->path );
/* extract relative path to essence file : "<firstparent>/<essence.file>" */
@ -164,7 +156,7 @@ aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_uri_
if (access (local_filepath, F_OK) != -1) {
// debug( "FOUND: %s", local_filepath );
retpath = local_filepath;
foundpath = local_filepath;
goto found;
}
@ -186,7 +178,7 @@ aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_uri_
if (access (local_filepath, F_OK) != -1) {
// debug( "FOUND: %s", local_filepath );
retpath = local_filepath;
foundpath = local_filepath;
goto found;
}
@ -198,7 +190,7 @@ aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_uri_
if (access (uri_filepath, F_OK) != -1) {
// debug( "FOUND: %s", uri_filepath );
retpath = uri_filepath;
foundpath = uri_filepath;
goto found;
}
@ -206,7 +198,7 @@ aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_uri_
if (access (uri->path, F_OK) != -1) {
// debug( "FOUND: %s", uri->path );
retpath = uri->path;
foundpath = uri->path;
goto found;
}
@ -265,7 +257,7 @@ aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_uri_
if (access (local_filepath, F_OK) != -1) {
// debug( "FOUND: %s", filepath );
retpath = local_filepath;
foundpath = local_filepath;
goto found;
}
@ -287,7 +279,7 @@ aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_uri_
if (access (local_filepath, F_OK) != -1) {
// debug( "FOUND: %s", filepath );
retpath = local_filepath;
foundpath = local_filepath;
goto found;
}
@ -297,7 +289,15 @@ aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_uri_
// debug("File not found");
found:
retpath = laaf_util_c99strdup (retpath);
if (foundpath) {
retpath = laaf_util_str2wstr (foundpath);
if (retpath == NULL) {
error ("Could not convert foundpath from str to wstr : %s", foundpath);
goto err;
}
}
goto end;
err:
@ -414,7 +414,7 @@ aafi_extract_audio_essence (AAF_Iface* aafi, aafiAudioEssence* audioEssence, con
memset (&wavBext, 0x00, sizeof (wavBext));
memcpy (wavBext.umid, audioEssence->sourceMobID, sizeof (aafMobID_t));
if (audioEssence->mobSlotEditRate) {
wavBext.time_reference = eu2sample (audioEssence->samplerate, audioEssence->mobSlotEditRate, audioEssence->timeReference);
wavBext.time_reference = laaf_util_converUnit (audioEssence->timeReference, audioEssence->mobSlotEditRate, audioEssence->samplerateRational);
}
if (datasz >= (uint32_t)-1) {
@ -443,10 +443,10 @@ aafi_extract_audio_essence (AAF_Iface* aafi, aafiAudioEssence* audioEssence, con
goto err;
}
reqlen = swprintf (audioEssence->usable_file_path, strlen (filepath) + 1, L"%" WPRIs, filepath);
audioEssence->usable_file_path = laaf_util_str2wstr (filepath);
if (reqlen < 0) {
error ("Failed setting usable_file_path");
if (audioEssence->usable_file_path == NULL) {
error ("Could not convert usable_file_path from str to wstr : %s", filepath);
goto err;
}
@ -473,94 +473,118 @@ end:
}
int
aafi_parse_audio_summary (AAF_Iface* aafi, aafiAudioEssence* audioEssence)
aafi_parse_audio_essence (AAF_Iface* aafi, aafiAudioEssence* audioEssence)
{
// laaf_util_dump_hex( audioEssence->summary->val, audioEssence->summary->len );
int rc = 0;
char* externalFilePath = NULL;
FILE* fp = NULL;
// aafi->dbg->_dbg_msg_pos += laaf_util_dump_hex( audioEssence->summary->val, audioEssence->summary->len, &aafi->dbg->_dbg_msg, &aafi->dbg->_dbg_msg_size, aafi->dbg->_dbg_msg_pos );
int rc = 0;
char* externalFilePath = NULL;
FILE* fp = NULL;
struct RIFFAudioFile RIFFAudioFile;
if (audioEssence->is_embedded) {
if (audioEssence->summary == NULL) {
warning ("TODO: Audio essence has no summary. TODO: Should try essence data stream ?");
/* try audioEssence->summary first, for both embedded and external */
if (audioEssence->summary) {
rc = riff_parseAudioFile (&RIFFAudioFile, RIFF_PARSE_AAF_SUMMARY, &embeddedAudioDataReaderCallback, audioEssence->summary->val, &audioEssence->summary->len, aafi, aafi->dbg);
if (rc < 0) {
warning ("Could not parse essence summary of %ls", audioEssence->file_name);
if (audioEssence->is_embedded) {
return -1;
}
} else {
audioEssence->channels = RIFFAudioFile.channels;
audioEssence->samplerate = RIFFAudioFile.sampleRate;
audioEssence->samplesize = RIFFAudioFile.sampleSize;
audioEssence->length = RIFFAudioFile.sampleCount;
audioEssence->samplerateRational->numerator = audioEssence->samplerate;
audioEssence->samplerateRational->denominator = 1;
return 0;
}
} else if (audioEssence->is_embedded) {
if (audioEssence->type != AAFI_ESSENCE_TYPE_PCM) {
warning ("TODO: Embedded audio essence has no summary. Should we try essence data stream ?");
}
return -1;
} else if (!audioEssence->usable_file_path) {
// warning( "Can't parse a missing external essence file" );
return -1;
}
if (laaf_util_fop_is_wstr_fileext (audioEssence->usable_file_path, L"wav") ||
laaf_util_fop_is_wstr_fileext (audioEssence->usable_file_path, L"wave") ||
laaf_util_fop_is_wstr_fileext (audioEssence->usable_file_path, L"aif") ||
laaf_util_fop_is_wstr_fileext (audioEssence->usable_file_path, L"aiff") ||
laaf_util_fop_is_wstr_fileext (audioEssence->usable_file_path, L"aifc")) {
externalFilePath = laaf_util_wstr2str (audioEssence->usable_file_path);
if (externalFilePath == NULL) {
error ("Could not convert usable_file_path from wstr to str : %ls", audioEssence->usable_file_path);
goto err;
}
/*
* Adobe Premiere Pro, embedded mp3/mp4 files converted to PCM/AIFF on export, AAFClassID_AIFCDescriptor, 'COMM' is valid.
* ______________________________ Hex Dump ______________________________
*
* 46 4f 52 4d 00 00 00 32 41 49 46 43 43 4f 4d 4d | FORM...2 AIFCCOMM
* 00 00 00 26 00 01 00 00 00 00 00 10 40 0e bb 80 | ........ ........
* 00 00 00 00 00 00 4e 4f 4e 45 0e 4e 6f 74 20 43 | ......NO NE.Not.C
* 6f 6d 70 72 65 73 73 65 64 00 | ompresse d.
* ______________________________________________________________________
*/
fp = fopen (externalFilePath, "rb");
// laaf_util_dump_hex( audioEssence->summary->val, audioEssence->summary->len );
if (fp == NULL) {
error ("Could not open external audio essence file for reading : %s", externalFilePath);
goto err;
}
rc = riff_parseAudioFile (&RIFFAudioFile, RIFF_PARSE_ONLY_HEADER, &embeddedAudioDataReaderCallback, audioEssence->summary->val, &audioEssence->summary->len, aafi, aafi->dbg);
rc = riff_parseAudioFile (&RIFFAudioFile, 0, &externalAudioDataReaderCallback, fp, externalFilePath, aafi, aafi->dbg);
if (rc < 0) {
warning ("TODO: Could not parse embedded essence summary. Should try essence data stream ?");
error ("Failed parsing external audio essence file : %s", externalFilePath);
goto err;
}
if (audioEssence->channels > 0 && audioEssence->channels != RIFFAudioFile.channels) {
warning ("%ls : summary channel count (%i) mismatch located file (%i)", audioEssence->usable_file_path, audioEssence->channels, RIFFAudioFile.channels);
}
if (audioEssence->samplerate > 0 && audioEssence->samplerate != RIFFAudioFile.sampleRate) {
warning ("%ls : summary samplerate (%i) mismatch located file (%i)", audioEssence->usable_file_path, audioEssence->samplerate, RIFFAudioFile.sampleRate);
}
if (audioEssence->samplesize > 0 && audioEssence->samplesize != RIFFAudioFile.sampleSize) {
warning ("%ls : summary samplesize (%i) mismatch located file (%i)", audioEssence->usable_file_path, audioEssence->samplesize, RIFFAudioFile.sampleSize);
}
if (audioEssence->length > 0 && audioEssence->length != RIFFAudioFile.sampleCount) {
warning ("%ls : summary samplecount (%" PRIi64 ") mismatch located file (%" PRIi64 ")", audioEssence->usable_file_path, audioEssence->length, RIFFAudioFile.sampleCount);
}
audioEssence->channels = RIFFAudioFile.channels;
audioEssence->samplerate = RIFFAudioFile.sampleRate;
audioEssence->samplesize = RIFFAudioFile.sampleSize;
audioEssence->length = RIFFAudioFile.duration;
audioEssence->length = RIFFAudioFile.sampleCount;
audioEssence->samplerateRational->numerator = audioEssence->samplerate;
audioEssence->samplerateRational->denominator = 1;
} else {
/* TODO: can external essence have audioEssence->summary too ? If mp3 (Resolve 18.5.aaf) ? */
/*
* should be considered as a non-pcm audio format
*
04317 AAFClassID_TimelineMobSlot [slot:6 track:4] (DataDef : AAFDataDef_Sound) : Audio 4 - Layered Audio Editing
01943 AAFClassID_Sequence
02894 AAFClassID_SourceClip
02899 AAFClassID_MasterMob (UsageCode: n/a) : speech-sample
04405 AAFClassID_TimelineMobSlot [slot:1 track:1] (DataDef : AAFDataDef_Sound)
03104 AAFClassID_SourceClip
04140 AAFClassID_SourceMob (UsageCode: n/a) : speech-sample
01287 AAFClassID_PCMDescriptor
01477 AAFClassID_NetworkLocator : file:///C:/Users/user/Desktop/libAAF/test/res/speech-sample.mp3
*
*/
externalFilePath = aafi_locate_external_essence_file (aafi, audioEssence->original_file_path, aafi->ctx.options.media_location);
audioEssence->type = AAFI_ESSENCE_TYPE_UNK;
if (externalFilePath == NULL) {
error ("Could not locate external audio essence file '%ls'", audioEssence->original_file_path);
return -1;
}
audioEssence->usable_file_path = malloc ((strlen (externalFilePath) + 1) * sizeof (wchar_t));
if (audioEssence->usable_file_path == NULL) {
error ("Could not allocate memory : %s", strerror (errno));
goto err;
}
rc = swprintf (audioEssence->usable_file_path, strlen (externalFilePath) + 1, L"%" WPRIs, externalFilePath);
if (rc < 0) {
error ("Failed setting usable_file_path");
goto err;
}
if (laaf_util_fop_is_wstr_fileext (audioEssence->original_file_path, L"wav") ||
laaf_util_fop_is_wstr_fileext (audioEssence->original_file_path, L"wave") ||
laaf_util_fop_is_wstr_fileext (audioEssence->original_file_path, L"aif") ||
laaf_util_fop_is_wstr_fileext (audioEssence->original_file_path, L"aiff") ||
laaf_util_fop_is_wstr_fileext (audioEssence->original_file_path, L"aifc")) {
fp = fopen (externalFilePath, "rb");
if (fp == NULL) {
error ("Could not open external audio essence file for reading : %s", externalFilePath);
goto err;
}
rc = riff_parseAudioFile (&RIFFAudioFile, RIFF_PARSE_ONLY_HEADER, &externalAudioDataReaderCallback, fp, externalFilePath, aafi, aafi->dbg);
if (rc < 0) {
error ("Failed parsing external audio essence file : %s", externalFilePath);
goto err;
}
audioEssence->channels = RIFFAudioFile.channels;
audioEssence->samplerate = RIFFAudioFile.sampleRate;
audioEssence->samplesize = RIFFAudioFile.sampleSize;
audioEssence->length = RIFFAudioFile.duration;
}
// /* clears any wrong data previously retrieved out of AAFClassID_PCMDescriptor */
// audioEssence->samplerate = 0;
// audioEssence->samplesize = 0;
}
rc = 0;
@ -586,12 +610,12 @@ embeddedAudioDataReaderCallback (unsigned char* buf, size_t offset, size_t reqLe
size_t datasz = *(size_t*)user2;
AAF_Iface* aafi = (AAF_Iface*)user3;
if (offset >= datasz) {
if (offset > datasz) {
error ("Requested data starts beyond data length");
return -1;
}
if (offset + reqLen >= datasz) {
if (offset + reqLen > datasz) {
reqLen = datasz - (offset + reqLen);
}

File diff suppressed because it is too large Load Diff

View File

@ -75,47 +75,37 @@ aafi_alloc (AAF_Data* aafd)
aafi->dbg = laaf_new_debug ();
if (aafi->dbg == NULL) {
return NULL;
goto err;
}
aafi->Audio = calloc (sizeof (aafiAudio), sizeof (unsigned char));
if (aafi->Audio == NULL) {
return NULL;
goto err;
}
aafi->Audio->Essences = NULL;
aafi->Audio->samplerate = 0;
aafi->Audio->samplesize = 0;
aafi->Audio->Tracks = NULL;
aafi->Audio->track_count = 0;
aafi->Audio->length = 0;
aafi->Video = calloc (sizeof (aafiVideo), sizeof (unsigned char));
if (aafi->Video == NULL) {
return NULL;
goto err;
}
aafi->Video->Essences = NULL;
aafi->Video->Tracks = NULL;
aafi->Video->length = 0;
if (aafd != NULL) {
aafi->aafd = aafd;
} else {
aafi->aafd = aaf_alloc (aafi->dbg);
if (aafi->aafd == NULL) {
goto err;
}
}
aafi->Markers = NULL;
aafi->compositionName = NULL;
aafi->ctx.is_inside_derivation_chain = 0;
aafi->ctx.options.forbid_nonlatin_filenames = 0;
aafi->ctx.options.trace = 0;
return aafi;
err:
aafi_release (&aafi);
return NULL;
}
void
@ -174,17 +164,16 @@ aafi_set_option_str (AAF_Iface* aafi, const char* optname, const char* val)
aafi->ctx.options.dump_class_aaf_properties = NULL;
}
if (val == NULL)
if (val == NULL) {
return 0;
}
aafi->ctx.options.dump_class_aaf_properties = malloc ((strlen (val) + 1) * sizeof (wchar_t));
aafi->ctx.options.dump_class_aaf_properties = laaf_util_str2wstr (val);
if (aafi->ctx.options.dump_class_aaf_properties == NULL) {
return -1;
}
swprintf (aafi->ctx.options.dump_class_aaf_properties, strlen (val) + 1, L"%" WPRIs, val);
return 0;
} else if (strcmp (optname, "dump_class_raw_properties") == 0) {
if (aafi->ctx.options.dump_class_raw_properties) {
@ -192,17 +181,16 @@ aafi_set_option_str (AAF_Iface* aafi, const char* optname, const char* val)
aafi->ctx.options.dump_class_raw_properties = NULL;
}
if (val == NULL)
if (val == NULL) {
return 0;
}
aafi->ctx.options.dump_class_raw_properties = malloc ((strlen (val) + 1) * sizeof (wchar_t));
aafi->ctx.options.dump_class_raw_properties = laaf_util_str2wstr (val);
if (aafi->ctx.options.dump_class_raw_properties == NULL) {
return -1;
}
swprintf (aafi->ctx.options.dump_class_raw_properties, strlen (val) + 1, L"%" WPRIs, val);
return 0;
}
@ -212,8 +200,9 @@ aafi_set_option_str (AAF_Iface* aafi, const char* optname, const char* val)
void
aafi_release (AAF_Iface** aafi)
{
if (*aafi == NULL)
if (*aafi == NULL) {
return;
}
aaf_release (&(*aafi)->aafd);
@ -541,6 +530,20 @@ aafi_freeAudioClip (aafiAudioClip* audioClip)
if (audioClip->automation != NULL) {
aafi_freeAudioGain (audioClip->automation);
}
aafi_freeAudioEssencePointer (audioClip->essencePointerList);
}
void
aafi_freeAudioEssencePointer (aafiAudioEssencePointer* essencePointer)
{
aafiAudioEssencePointer* next = NULL;
while (essencePointer) {
next = essencePointer->next;
free (essencePointer);
essencePointer = next;
}
}
void
@ -649,12 +652,9 @@ aafi_newAudioTrack (AAF_Iface* aafi)
return NULL;
}
track->Audio = aafi->Audio;
track->format = AAFI_TRACK_FORMAT_NOT_SET;
track->pan = NULL;
track->gain = NULL;
track->current_pos = 0;
track->next = NULL;
track->Audio = aafi->Audio;
track->format = AAFI_TRACK_FORMAT_NOT_SET;
track->next = NULL;
/* Add to track list */
@ -718,9 +718,8 @@ aafi_newVideoTrack (AAF_Iface* aafi)
return NULL;
}
track->Video = aafi->Video;
track->current_pos = 0;
track->next = NULL;
track->Video = aafi->Video;
track->next = NULL;
/* Add to track list */
@ -776,20 +775,52 @@ aafi_newAudioEssence (AAF_Iface* aafi)
return NULL;
}
audioEssence->next = aafi->Audio->Essences;
audioEssence->samplerateRational = malloc (sizeof (aafRational_t));
audioEssence->original_file_path = NULL;
audioEssence->usable_file_path = NULL;
audioEssence->file_name = NULL;
audioEssence->unique_file_name = NULL;
audioEssence->clip_count = 0;
audioEssence->user = NULL;
if (audioEssence->samplerateRational == NULL) {
return NULL;
}
audioEssence->samplerateRational->numerator = 1;
audioEssence->samplerateRational->denominator = 1;
audioEssence->next = aafi->Audio->Essences;
aafi->Audio->Essences = audioEssence;
return audioEssence;
}
aafiAudioEssencePointer*
aafi_newAudioEssencePointer (AAF_Iface* aafi, aafiAudioEssencePointer** list, aafiAudioEssence* audioEssence, uint32_t* essenceChannelNum)
{
aafiAudioEssencePointer* essencePointer = calloc (sizeof (aafiAudioEssencePointer), sizeof (char));
if (essencePointer == NULL) {
error ("%s.", strerror (errno));
return NULL;
}
essencePointer->aafi = aafi;
essencePointer->essence = audioEssence;
essencePointer->essenceChannel = (essenceChannelNum) ? *essenceChannelNum : 0;
if (*list) {
aafiAudioEssencePointer* last = *list;
while (last->next != NULL) {
last = last->next;
}
last->next = essencePointer;
} else {
*list = essencePointer;
essencePointer->aafiNext = aafi->Audio->essencePointerList;
aafi->Audio->essencePointerList = essencePointer;
}
return *list;
}
void
aafi_freeAudioEssences (aafiAudioEssence** audioEssence)
{
@ -818,6 +849,10 @@ aafi_freeAudioEssences (aafiAudioEssence** audioEssence)
free ((*audioEssence)->unique_file_name);
}
if ((*audioEssence)->samplerateRational != NULL) {
free ((*audioEssence)->samplerateRational);
}
free (*audioEssence);
}
@ -836,11 +871,6 @@ aafi_newVideoEssence (AAF_Iface* aafi)
videoEssence->next = aafi->Video->Essences;
videoEssence->original_file_path = NULL;
videoEssence->usable_file_path = NULL;
videoEssence->file_name = NULL;
videoEssence->unique_file_name = NULL;
aafi->Video->Essences = videoEssence;
return videoEssence;
@ -880,6 +910,35 @@ aafi_freeVideoEssences (aafiVideoEssence** videoEssence)
*videoEssence = NULL;
}
int
aafi_getAudioEssencePointerChannelCount (aafiAudioEssencePointer* essencePointerList)
{
/*
* If essencePointerList holds a single multichannel essence file and if
* essencePointer->essenceChannel is set, then clip is mono and audio comes
* from essencePointer->essenceChannel of essencePointer->essence file.
*
* If essencePointerList holds a single multichannel essence file and if
* essencePointer->essenceChannel is null, then clip is multichannel and
* clip channel count equals essence->channels.
*
* If essencePointerList holds multiple pointers to multiple essence files,
* then each file should be mono and describe a clip channel. Thus, clip
* channel count equals pointers count.
*/
int essencePointerCount = 0;
aafiAudioEssencePointer* essencePointer = NULL;
AAFI_foreachAudioEssencePointer (essencePointer, essencePointerList)
{
essencePointerCount++;
}
return (essencePointerCount > 1) ? essencePointerCount : (essencePointerList->essenceChannel) ? 1
: essencePointerList->essence->channels;
}
/**
* @}
*/

View File

@ -177,7 +177,7 @@ replace_clipfade_with_fade (AAF_Iface* aafi, aafiTimelineItem* Item)
if (Item->next->type == AAFI_AUDIO_CLIP) {
nextClip = (aafiAudioClip*)Item->next->data;
if (is_sample_accurate_edit (nextClip->Essence->file_name)) {
if (is_sample_accurate_edit (nextClip->essencePointerList->essence->file_name)) {
if (Item->next->next != NULL) {
nextClip = (aafiAudioClip*)Item->next->next->data;
@ -281,7 +281,7 @@ protools_post_processing (AAF_Iface* aafi /*, enum protools_options flags*/)
aafiAudioClip* audioClip = (aafiAudioClip*)audioItem->data;
wchar_t* clipName = audioClip->Essence->file_name;
wchar_t* clipName = audioClip->essencePointerList->essence->file_name;
if ((aafi->ctx.options.protools & PROTOOLS_REPLACE_CLIP_FADES) && is_rendered_fade (clipName)) {
replace_clipfade_with_fade (aafi, audioItem);

View File

@ -124,7 +124,7 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
size_t bytesRead = readerCallback ((unsigned char*)&riff, 0, sizeof (riff), user1, user2, user3);
if (bytesRead < sizeof (riff)) {
error ("Could not read file");
error ("Could not read file header");
return -1;
}
@ -152,8 +152,6 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
return -1;
}
// debug( "%.4s %.4s (%u bytes)", riff.ckid, riff.format, riff.cksz );
size_t filesize = riff.cksz + sizeof (chunk);
size_t pos = sizeof (struct riffHeaderChunk);
@ -161,7 +159,7 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
bytesRead = readerCallback ((unsigned char*)&chunk, pos, sizeof (chunk), user1, user2, user3);
if (bytesRead < sizeof (chunk)) {
error ("Could not read chunk @ %" PRIu64 " (%" PRIu64 " bytes returned)", pos, bytesRead);
error ("Could not read chunk \"%.4s\" @ %" PRIu64 " (%" PRIu64 " bytes returned)", chunk.ckid, pos, bytesRead);
break;
}
@ -169,7 +167,7 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
chunk.cksz = BE2LE32 (chunk.cksz);
}
// debug( "Got chunk : %.4s (%u bytes)", chunk.ckid, chunk.cksz );
debug ("Got chunk \"%.4s\" (%u bytes) @ %" PRIu64 " (%" PRIu64 " bytes returned)", chunk.ckid, chunk.cksz, pos, bytesRead);
if (!be) { /* WAVE */
@ -181,6 +179,11 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
bytesRead = readerCallback ((unsigned char*)&wavFmtChunk, pos, sizeof (wavFmtChunk), user1, user2, user3);
if (bytesRead < sizeof (wavFmtChunk)) {
error ("Could not read chunk \"%.4s\" content @ %" PRIu64 " (%" PRIu64 " bytes returned)", chunk.ckid, pos, bytesRead);
break;
}
RIFFAudioFile->channels = wavFmtChunk.channels;
RIFFAudioFile->sampleSize = wavFmtChunk.bits_per_sample;
RIFFAudioFile->sampleRate = wavFmtChunk.samples_per_sec;
@ -193,7 +196,11 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
chunk.ckid[2] == 't' &&
chunk.ckid[3] == 'a') {
if (RIFFAudioFile->channels > 0 && RIFFAudioFile->sampleSize > 0) {
RIFFAudioFile->duration = chunk.cksz / RIFFAudioFile->channels / (RIFFAudioFile->sampleSize / 8);
RIFFAudioFile->sampleCount = chunk.cksz / RIFFAudioFile->channels / (RIFFAudioFile->sampleSize / 8);
}
if (flags & RIFF_PARSE_AAF_SUMMARY) {
return 0;
}
}
} else { /* AIFF */
@ -206,29 +213,40 @@ riff_parseAudioFile (struct RIFFAudioFile* RIFFAudioFile, enum RIFF_PARSER_FLAGS
bytesRead = readerCallback ((unsigned char*)&aiffCOMMChunk, pos, sizeof (aiffCOMMChunk), user1, user2, user3);
RIFFAudioFile->channels = BE2LE16 (aiffCOMMChunk.numChannels);
RIFFAudioFile->sampleSize = BE2LE16 (aiffCOMMChunk.sampleSize);
RIFFAudioFile->sampleRate = beExtended2leUint32 (aiffCOMMChunk.sampleRate);
RIFFAudioFile->duration = BE2LE32 (aiffCOMMChunk.numSampleFrames);
if (bytesRead < sizeof (aiffCOMMChunk)) {
error ("Could not read chunk \"%.4s\" content @ %" PRIu64 " (%" PRIu64 " bytes returned)", chunk.ckid, pos, bytesRead);
break;
}
RIFFAudioFile->channels = BE2LE16 (aiffCOMMChunk.numChannels);
RIFFAudioFile->sampleSize = BE2LE16 (aiffCOMMChunk.sampleSize);
RIFFAudioFile->sampleRate = beExtended2leUint32 (aiffCOMMChunk.sampleRate);
RIFFAudioFile->sampleCount = BE2LE32 (aiffCOMMChunk.numSampleFrames);
if (flags & RIFF_PARSE_ONLY_HEADER) {
return 0;
}
}
/*
* We don't care about AIFF "SSND" chunk because we already know duration
* from "COMM". Could we double check validity of duration by checking
* "SSND" chunk size, like we do with WAV "DATA" chunk ? is it possible
* with AAF audio file summary ?
*/
} else if (chunk.ckid[0] == 'S' &&
chunk.ckid[1] == 'S' &&
chunk.ckid[2] == 'N' &&
chunk.ckid[3] == 'D') {
/*
* Samplecount should be already set with numSampleFrames in COMM chunk.
* However in AAF (AIFCDescriptor::Summary), numSampleFrames is often null,
* so we must extract samplecount out of SSND chunk, like we do with wav DATA chunk.
*/
uint64_t sampleCount = chunk.cksz / RIFFAudioFile->channels / (RIFFAudioFile->sampleSize / 8);
// else
// if ( chunk.ckid[0] == 'S' &&
// chunk.ckid[1] == 'S' &&
// chunk.ckid[2] == 'N' &&
// chunk.ckid[3] == 'D' )
// {
// }
if (RIFFAudioFile->sampleCount > 0 && RIFFAudioFile->sampleCount != sampleCount) {
debug ("Sample count retrieved from COMM chunk (%" PRIu64 ") does not match SSND chunk (%" PRIu64 ")", RIFFAudioFile->sampleCount, sampleCount);
}
RIFFAudioFile->sampleCount = sampleCount;
if (flags & RIFF_PARSE_AAF_SUMMARY) {
return 0;
}
}
}
pos += chunk.cksz + sizeof (chunk);

View File

@ -25,13 +25,13 @@
#include "aaf/AAFIface.h"
char*
wchar_t*
aafi_locate_external_essence_file (AAF_Iface* aafi, const wchar_t* original_file_path, const char* search_location);
int
aafi_extract_audio_essence (AAF_Iface* aafi, aafiAudioEssence* audioEssence, const char* outfilepath, const wchar_t* forcedFileName);
int
aafi_parse_audio_summary (AAF_Iface* aafi, aafiAudioEssence* audioEssence);
aafi_parse_audio_essence (AAF_Iface* aafi, aafiAudioEssence* audioEssence);
#endif // !__AAFIAudioFiles_h__

View File

@ -42,6 +42,7 @@ enum aafiEssenceType {
AAFI_ESSENCE_TYPE_WAVE = 0x02,
AAFI_ESSENCE_TYPE_AIFC = 0x03,
AAFI_ESSENCE_TYPE_BWAV = 0x04,
AAFI_ESSENCE_TYPE_UNK = 0xff, /* non-pcm */
};
/**
@ -234,15 +235,20 @@ typedef struct aafiAudioGain {
typedef struct aafiAudioGain aafiAudioPan;
typedef struct aafiAudioEssence {
wchar_t* original_file_path; // NetworkLocator::URLString the original URI hold in AAF
wchar_t* original_file_path; // NetworkLocator::URLString the original external essence URI holded in AAF
wchar_t* usable_file_path; // Holds a real usable file path, once an embedded essence has been extracted, or once en external essence has been found.
wchar_t* file_name; // MasterMob::Name the original file name. Might be NULL if MasterMob has no name. One should always use unique_file_name which is guaranted to be set.
wchar_t* unique_file_name; // unique name generated from file_name. Sometimes, multiple files share the same names so this unique name should be used on export.
uint16_t clip_count; // number of clips with this essence
uint16_t clip_count; // number of clips using this essence
/* total samples for 1 channel (no matter channel count). (duration / sampleRate) = duration in seconds */
uint64_t length; // Length of Essence Data
/*
* total samples for 1 channel (no matter channel count).
* Might be retrieved from FileDescriptor::Length property,
* or from WAV/AIFF summary or file :
* (data chunk size / channels / samplesize / 8)
*/
uint64_t length;
cfbNode* node; // The node holding the audio stream if embedded
@ -255,14 +261,18 @@ typedef struct aafiAudioEssence {
enum aafiEssenceType type; // depends on PCMDescriptor WAVEDescriptor AIFCDescriptor
/*
* is only set if FileSourceMob contains EssenceData
*/
uint8_t is_embedded;
aafProperty* summary; // WAVEDescriptor AIFCDescriptor
// uint32_t format;
uint32_t samplerate;
int16_t samplesize;
int16_t channels;
uint32_t samplerate;
aafRational_t* samplerateRational; // eg. { 48000, 1 }
int16_t samplesize;
int16_t channels;
aafRational_t* mobSlotEditRate;
@ -277,10 +287,22 @@ typedef struct aafiAudioEssence {
void* user;
// TODO peakEnveloppe
struct aafiAudioEssence* next;
struct aafiAudioEssence* next; // aafi->Audio->essences
} aafiAudioEssence;
typedef struct aafiAudioEssencePointer {
aafiAudioEssence* essence; // single essence, not list !
int essenceChannel; // channel selector inside multichannel essence. If zero, then all essence channels must be used.
void* user;
struct aafiAudioEssencePointer* next; // audioClip->essenceGroup
struct aafiAudioEssencePointer* aafiNext; // aafi->Audio->essenceGroup
struct AAF_Iface* aafi;
} aafiAudioEssencePointer;
typedef struct aafiVideoEssence {
wchar_t* original_file_path; // NetworkLocator::URLString should point to original essence file if external (and in some cases, points to the AAF itself if internal..)
wchar_t* usable_file_path; // TODO, not that used.. to be tweaked. ---- Holds the file path, once the essence has been exported, copied or linked.
@ -318,8 +340,8 @@ struct aafiVideoTrack;
typedef struct aafiAudioClip {
struct aafiAudioTrack* track;
aafiAudioEssence* Essence;
int channels; // channel count of clip (might be different of essence->channels)
aafiAudioEssencePointer* essencePointerList;
/*
* Some editors (like Resolve) support automation attached to a clip AND a fixed value clip gain
*/
@ -338,22 +360,26 @@ typedef struct aafiAudioClip {
* Start position in source file, set from SourceClip::StartTime
*
* « Specifies the offset from the origin of the referenced Mob MobSlot in edit units
* determined by the SourceClip objects context.
* determined by the SourceClip objects context. »
*
* A SourceClips StartTime and Length values are in edit units determined by the slot
* owning the SourceClip.
* « A SourceClips StartTime and Length values are in edit units determined by the slot
* owning the SourceClip. »
* Informative note: If the SourceClip references a MobSlot that specifies a different
* « Informative note: If the SourceClip references a MobSlot that specifies a different
* edit rate than the MobSlot owning the SourceClip, the StartTime and Length are in
* edit units of the slot owning the SourceClip, and not edit units of the referenced slot.»
*/
aafPosition_t essence_offset; /* in edit unit, edit rate definition is aafiAudioTrack->edit_rate */
/*
* set with CompoMob's SourceClip::StartTime. In the case of an OperationGroup(AudioChannelCombiner),
* There is one SourceClip per audio channel. So even though it's very unlikely, there could possibly
* be one essence_offset per channel.
* Value is in edit unit, edit rate definition is aafiAudioTrack->edit_rate
*/
aafPosition_t essence_offset;
struct aafiTimelineItem* Item; // Corresponding timeline item, currently used in ardour to retrieve fades/x-fades
aafMobID_t* masterMobID; // MobID of the associated MasterMob (PID_SourceReference_SourceID)
} aafiAudioClip;
typedef struct aafiVideoClip {
@ -403,12 +429,6 @@ typedef struct aafiTimecode {
aafPosition_t start;
/**
* Timecode end in EditUnit. (session end)
*/
aafPosition_t end;
/**
* Frame per second.
*/
@ -561,17 +581,17 @@ typedef struct aafiAudio {
*/
aafPosition_t start;
aafPosition_t length;
aafRational_t length_editRate;
int64_t samplerate;
int16_t samplesize;
int16_t samplesize;
int64_t samplerate;
aafRational_t* samplerateRational; // eg. { 48000, 1 }
/**
* Holds the Essence list.
*/
aafiAudioEssence* Essences;
aafiAudioEssence* Essences;
aafiAudioEssencePointer* essencePointerList;
/**
* Holds the Track list.
@ -588,8 +608,6 @@ typedef struct aafiVideo {
*/
aafPosition_t start;
aafPosition_t length;
aafRational_t length_editRate;
/**
* Holds the Essence list.
@ -654,10 +672,10 @@ typedef struct aafiContext {
aafiVideoClip* current_video_clip;
int current_clip_is_muted;
int current_clip_is_combined; // Inside OperationGroup::AAFOperationDef_AudioChannelCombiner
int current_combined_clip_total_channel;
int current_combined_clip_channel_num; // current SourceClip represents channel num
int current_clip_is_combined; // Inside OperationGroup::AAFOperationDef_AudioChannelCombiner
int current_combined_clip_total_channel;
int current_combined_clip_channel_num; // current SourceClip represents channel num
aafPosition_t current_combined_clip_forced_length;
/* Transition */
aafiTransition* current_transition;
@ -713,11 +731,11 @@ typedef struct AAF_Iface {
wchar_t* compositionName;
aafPosition_t compositionStart; // set from aafi->Timecode->start
aafRational_t compositionStart_editRate;
aafPosition_t compositionStart; // sets from aafi->Timecode->start
aafRational_t* compositionStart_editRate;
aafPosition_t compositionLength;
aafRational_t compositionLength_editRate;
aafPosition_t compositionLength; // sets from the longest audio or video track->current_pos
aafRational_t* compositionLength_editRate; /* might be NULL if file empty ! */
aafiUserComment* Comments;
@ -740,30 +758,18 @@ typedef struct AAF_Iface {
item != NULL; \
item = item->next)
#define AAFI_foreachAudioEssencePointerInFile(essencePointer, aafi) \
for (essencePointer = aafi->Audio->essencePointerList; essencePointer != NULL; essencePointer = essencePointer->aafiNext)
#define AAFI_foreachAudioEssencePointer(essencePointer, essencePtrList) \
for (essencePointer = essencePtrList; essencePointer != NULL; essencePointer = essencePointer->next)
#define foreachEssence(essence, essenceList) \
for (essence = essenceList; essence != NULL; essence = essence->next)
#define foreachMarker(marker, aafi) \
for (marker = aafi->Markers; marker != NULL; marker = marker->next)
#define aeDuration_h(audioEssence) \
((audioEssence->samplerate == 0) ? 0 : ((uint16_t) (audioEssence->length / audioEssence->samplerate / (audioEssence->samplesize / 8)) / 3600))
#define aeDuration_m(audioEssence) \
((audioEssence->samplerate == 0) ? 0 : ((uint16_t) (audioEssence->length / audioEssence->samplerate / (audioEssence->samplesize / 8)) % 3600 / 60))
#define aeDuration_s(audioEssence) \
((audioEssence->samplerate == 0) ? 0 : ((uint16_t) (audioEssence->length / audioEssence->samplerate / (audioEssence->samplesize / 8)) % 3600 % 60))
#define aeDuration_ms(audioEssence) \
((audioEssence->samplerate == 0) ? 0 : ((uint16_t) (audioEssence->length / (audioEssence->samplerate / 1000) / (audioEssence->samplesize / 8)) % 3600000 % 60000 % 1000))
#define convertEditUnit(val, fromRate, toRate) \
(int64_t) ((val) * (aafRationalToFloat ((toRate)) * (1 / aafRationalToFloat ((fromRate)))))
#define eu2sample(samplerate, edit_rate, val) \
(int64_t) (val * (samplerate * (1 / aafRationalToFloat ((*edit_rate)))))
void
aafi_set_debug (AAF_Iface* aafi, verbosityLevel_e v, int ansicolor, FILE* fp, void (*callback) (struct dbg* dbg, void* ctxdata, int lib, int type, const char* srcfile, const char* srcfunc, int lineno, const char* msg, void* user), void* user);
@ -823,6 +829,9 @@ aafi_freeAudioPan (aafiAudioPan* pan);
void
aafi_freeAudioClip (aafiAudioClip* audioClip);
void
aafi_freeAudioEssencePointer (aafiAudioEssencePointer* audioEssenceGroupEntry);
void
aafi_freeTimelineItem (aafiTimelineItem** item);
@ -841,6 +850,9 @@ aafi_freeTransition (aafiTransition* trans);
aafiAudioEssence*
aafi_newAudioEssence (AAF_Iface* aafi);
aafiAudioEssencePointer*
aafi_newAudioEssencePointer (AAF_Iface* aafi, aafiAudioEssencePointer** list, aafiAudioEssence* audioEssence, uint32_t* essenceChannelNum);
void
aafi_freeAudioEssences (aafiAudioEssence** essences);
@ -850,6 +862,9 @@ aafi_newVideoEssence (AAF_Iface* aafi);
void
aafi_freeVideoEssences (aafiVideoEssence** videoEssence);
int
aafi_getAudioEssencePointerChannelCount (aafiAudioEssencePointer* essencePointerList);
/**
* @}
*/

View File

@ -33,6 +33,7 @@
enum RIFF_PARSER_FLAGS {
RIFF_PARSE_ONLY_HEADER = (1 << 0),
RIFF_PARSE_AAF_SUMMARY = (1 << 1),
};
struct RIFFAudioFile {
@ -40,7 +41,7 @@ struct RIFFAudioFile {
uint32_t sampleRate;
uint16_t sampleSize;
uint16_t channels;
uint64_t duration; /* total samples for 1 channel (no matter channel count). (duration / sampleRate) = duration in seconds */
uint64_t sampleCount; /* total samples for 1 channel (no matter channel count). (sampleCount / sampleRate) = duration in seconds */
};
PACK (struct riffHeaderChunk {

View File

@ -21,6 +21,7 @@
#ifndef __utils_h__
#define __utils_h__
#include "aaf/AAFTypes.h"
#include <stdarg.h>
#include <stdint.h>
@ -35,9 +36,13 @@ extern "C" {
* swprintf() specific string format identifiers
* https://learn.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-170#type
*/
#define WPRIs L"S" // char*
#define WPRIs L"S" // char*
#ifdef XBUILD_WIN
#define WPRIws L"s" // wchar_t*
#else
#define WPRIws L"ls" // wchar_t*
#endif
#else
#define DIR_SEP '/'
#define DIR_SEP_STR "/"
/*
@ -62,6 +67,15 @@ extern "C" {
#define ANSI_COLOR_BOLD(dbg) (((dbg)->ansicolor) ? "\x1b[1m" : "")
#define ANSI_COLOR_RESET(dbg) (((dbg)->ansicolor) ? "\x1b[0m" : "")
aafPosition_t
laaf_util_converUnit (aafPosition_t value, aafRational_t* valueEditRate, aafRational_t* destEditRate);
char*
laaf_util_wstr2str (const wchar_t* wstr);
wchar_t*
laaf_util_str2wstr (const char* str);
int
laaf_util_wstr_contains_nonlatin (const wchar_t* str);

View File

@ -1,2 +1,2 @@
#pragma once
#define LIBAAF_VERSION "v0.5-2-g4dfb754"
#define LIBAAF_VERSION "v0.6-45-g9171e40"

View File

@ -29,6 +29,81 @@
#define BUILD_PATH_DEFAULT_BUF_SIZE 1024
aafPosition_t
laaf_util_converUnit (aafPosition_t value, aafRational_t* valueEditRate, aafRational_t* destEditRate)
{
if (!valueEditRate || !destEditRate) {
return value;
}
if (valueEditRate->numerator == destEditRate->numerator &&
valueEditRate->denominator == destEditRate->denominator) {
/* same rate, no conversion */
return value;
}
double valueEditRateFloat = ((valueEditRate->denominator == 0) ? 0.0 : ((float)valueEditRate->numerator / valueEditRate->denominator));
double destEditRateFloat = ((destEditRate->denominator == 0) ? 0.0 : ((float)destEditRate->numerator / destEditRate->denominator));
if (valueEditRateFloat == 0) {
return 0;
}
return value * (destEditRateFloat / valueEditRateFloat);
}
char*
laaf_util_wstr2str (const wchar_t* wstr)
{
if (wstr == NULL) {
return NULL;
}
size_t strsz = wcslen (wstr) + 1;
char* str = malloc (strsz);
if (str == NULL) {
// error( "Could not allocate memory : %s", strerror(errno) );
return NULL;
}
int rc = snprintf (str, strsz, "%ls", wstr);
if (rc < 0 || (unsigned)rc >= strsz) {
// error( "Failed converting wide char str to byte char str%s", (reqlen < 0) ? " : encoding error" : "" );
free (str);
return NULL;
}
return str;
}
wchar_t*
laaf_util_str2wstr (const char* str)
{
if (str == NULL) {
return NULL;
}
size_t strsz = strlen (str) + 1;
wchar_t* wstr = malloc (strsz * sizeof (wchar_t));
if (str == NULL) {
// error( "Could not allocate memory : %s", strerror(errno) );
return NULL;
}
int rc = swprintf (wstr, strsz, L"%" WPRIs, str);
if (rc < 0 || (unsigned)rc >= strsz) {
// error( "Failed converting byte char str to wide char str%s", (reqlen < 0) ? " : encoding error" : "" );
free (wstr);
return NULL;
}
return wstr;
}
int
laaf_util_wstr_contains_nonlatin (const wchar_t* str)
{

View File

@ -38,7 +38,7 @@ def options(opt):
def configure(conf):
if conf.is_defined('USE_EXTERNAL_LIBS'):
autowaf.check_pkg(conf, 'libaaf', uselib_store='LIBAAF', mandatory=True)
autowaf.check_pkg(conf, 'libaaf', uselib_store='LIBAAF', mandatory=True, atleast_version='0.6.0')
def build(bld):
if bld.is_defined('USE_EXTERNAL_LIBS'):