bool USoundWave::IsCachedCookedPlatformDataLoaded( const ITargetPlatform* TargetPlatform ) { if (TargetPlatform->SupportsFeature(ETargetPlatformFeatures::AudioStreaming) && IsStreaming()) { // Retrieve format to cache for targetplatform. FName PlatformFormat = TargetPlatform->GetWaveFormat(this); // find format data by comparing derived data keys. FString DerivedDataKey; GetStreamedAudioDerivedDataKeySuffix(*this, PlatformFormat, DerivedDataKey); FStreamedAudioPlatformData *PlatformData = CookedPlatformData.FindRef(DerivedDataKey); if (PlatformData == NULL) { // we havne't called begincache return false; } if (PlatformData->AsyncTask && PlatformData->AsyncTask->IsWorkDone()) { PlatformData->FinishCache(); } return PlatformData->IsFinishedCache(); } return true; }
void USoundWave::SerializeCookedPlatformData(FArchive& Ar) { if (IsTemplate()) { return; } DECLARE_SCOPE_CYCLE_COUNTER( TEXT("USoundWave::SerializeCookedPlatformData"), STAT_SoundWave_SerializeCookedPlatformData, STATGROUP_LoadTime ); #if WITH_EDITORONLY_DATA if (Ar.IsCooking() && Ar.IsPersistent()) { check(!Ar.CookingTarget()->IsServerOnly()); FName PlatformFormat = Ar.CookingTarget()->GetWaveFormat(this); FString DerivedDataKey; GetStreamedAudioDerivedDataKey(*this, PlatformFormat, DerivedDataKey); FStreamedAudioPlatformData *PlatformDataToSave = CookedPlatformData.FindRef(DerivedDataKey); if (PlatformDataToSave == NULL) { PlatformDataToSave = new FStreamedAudioPlatformData(); PlatformDataToSave->Cache(*this, PlatformFormat, EStreamedAudioCacheFlags::InlineChunks | EStreamedAudioCacheFlags::Async); CookedPlatformData.Add(DerivedDataKey, PlatformDataToSave); } PlatformDataToSave->FinishCache(); PlatformDataToSave->Serialize(Ar, this); } else #endif // #if WITH_EDITORONLY_DATA { check(!FPlatformProperties::IsServerOnly()); CleanupCachedRunningPlatformData(); check(RunningPlatformData == NULL); // Don't serialize streaming data on servers, even if this platform supports streaming in theory RunningPlatformData = new FStreamedAudioPlatformData(); RunningPlatformData->Serialize(Ar, this); } }
/** Does the work to cache derived data. Safe to call from any thread. */ void DoWork() { TArray<uint8> RawDerivedData; bool bForceRebuild = (CacheFlags & EStreamedAudioCacheFlags::ForceRebuild) != 0; bool bInlineChunks = (CacheFlags & EStreamedAudioCacheFlags::InlineChunks) != 0; bool bForDDC = (CacheFlags & EStreamedAudioCacheFlags::ForDDCBuild) != 0; bool bAllowAsyncBuild = (CacheFlags & EStreamedAudioCacheFlags::AllowAsyncBuild) != 0; if (!bForceRebuild && GetDerivedDataCacheRef().GetSynchronous(*DerivedData->DerivedDataKey, RawDerivedData)) { FMemoryReader Ar(RawDerivedData, /*bIsPersistent=*/ true); DerivedData->Serialize(Ar, NULL); bSucceeded = true; if (bForDDC) { for (int32 Index = 0; Index < DerivedData->NumChunks; ++Index) { if (!DerivedData->TryLoadChunk(Index, NULL)) { bSucceeded = false; break; } } } else if (bInlineChunks) { bSucceeded = DerivedData->TryInlineChunkData(); } else { bSucceeded = DerivedData->AreDerivedChunksAvailable(); } } else if (bAllowAsyncBuild) { BuildStreamedAudio(); } }
void USoundWave::BeginCacheForCookedPlatformData(const ITargetPlatform *TargetPlatform) { if (TargetPlatform->SupportsFeature(ETargetPlatformFeatures::AudioStreaming) && IsStreaming()) { // Retrieve format to cache for targetplatform. FName PlatformFormat = TargetPlatform->GetWaveFormat(this); uint32 CacheFlags = EStreamedAudioCacheFlags::Async | EStreamedAudioCacheFlags::InlineChunks; // If source data is resident in memory then allow the streamed audio to be built // in a background thread. if (GetCompressedData(PlatformFormat)->IsBulkDataLoaded()) { CacheFlags |= EStreamedAudioCacheFlags::AllowAsyncBuild; } // find format data by comparing derived data keys. FString DerivedDataKey; GetStreamedAudioDerivedDataKeySuffix(*this, PlatformFormat, DerivedDataKey); FStreamedAudioPlatformData *PlatformData = CookedPlatformData.FindRef(DerivedDataKey); if (PlatformData == NULL) { PlatformData = new FStreamedAudioPlatformData(); PlatformData->Cache( *this, PlatformFormat, CacheFlags ); CookedPlatformData.Add(DerivedDataKey, PlatformData); } } Super::BeginCacheForCookedPlatformData(TargetPlatform); }
/** Build the streamed audio. This function is safe to call from any thread. */ void BuildStreamedAudio() { GetStreamedAudioDerivedDataKeySuffix(SoundWave, AudioFormatName, KeySuffix); DerivedData->Chunks.Empty(); ITargetPlatformManagerModule* TPM = GetTargetPlatformManager(); const IAudioFormat* AudioFormat = NULL; if (TPM) { AudioFormat = TPM->FindAudioFormat(AudioFormatName); } if (AudioFormat) { DerivedData->AudioFormat = AudioFormatName; FByteBulkData* CompressedData = SoundWave.GetCompressedData(AudioFormatName); TArray<uint8> CompressedBuffer; CompressedBuffer.Empty(CompressedData->GetBulkDataSize()); CompressedBuffer.AddUninitialized(CompressedData->GetBulkDataSize()); void* BufferData = CompressedBuffer.GetData(); CompressedData->GetCopy(&BufferData, false); TArray<TArray<uint8>> ChunkBuffers; if (AudioFormat->SplitDataForStreaming(CompressedBuffer, ChunkBuffers)) { for (int32 ChunkIndex = 0; ChunkIndex < ChunkBuffers.Num(); ++ChunkIndex) { FStreamedAudioChunk* NewChunk = new(DerivedData->Chunks) FStreamedAudioChunk(); NewChunk->DataSize = ChunkBuffers[ChunkIndex].Num(); NewChunk->BulkData.Lock(LOCK_READ_WRITE); void* NewChunkData = NewChunk->BulkData.Realloc(ChunkBuffers[ChunkIndex].Num()); FMemory::Memcpy(NewChunkData, ChunkBuffers[ChunkIndex].GetData(), ChunkBuffers[ChunkIndex].Num()); NewChunk->BulkData.Unlock(); } } else { // Could not split so copy compressed data into a single chunk FStreamedAudioChunk* NewChunk = new(DerivedData->Chunks) FStreamedAudioChunk(); NewChunk->DataSize = CompressedBuffer.Num(); NewChunk->BulkData.Lock(LOCK_READ_WRITE); void* NewChunkData = NewChunk->BulkData.Realloc(CompressedBuffer.Num()); FMemory::Memcpy(NewChunkData, CompressedBuffer.GetData(), CompressedBuffer.Num()); NewChunk->BulkData.Unlock(); } DerivedData->NumChunks = DerivedData->Chunks.Num(); // Store it in the cache. PutDerivedDataInCache(DerivedData, KeySuffix); } if (DerivedData->Chunks.Num()) { bool bInlineChunks = (CacheFlags & EStreamedAudioCacheFlags::InlineChunks) != 0; bSucceeded = !bInlineChunks || DerivedData->TryInlineChunkData(); } else { UE_LOG(LogAudio, Warning, TEXT("Failed to build %s derived data for %s"), *AudioFormatName.GetPlainNameString(), *SoundWave.GetPathName() ); } }