2021年7月30日金曜日

Unreal Engine 4 でPakをLZ4圧縮

はじめに

LZ4に正式対応し, Pak File Compression Format(s)で指定できるように思えますが, そんなことはないです.

原因

FCompression::IsFormatValidが原因と思われます. コメントからすると, 不具合のように見えます.

  1. bool FCompression::IsFormatValid(FName FormatName)
  2. {
  3. // build in formats are always valid
  4. if (FormatName == NAME_Zlib || FormatName == NAME_Gzip)
  5. {
  6. return true;
  7. }
  8. // otherwise, if we can get the format class, we are good!
  9. return GetCompressionFormat(FormatName, false) != nullptr;
  10. }

圧縮形式

zlibのチェックサム計算も軽くはないことに注意です.

  • zlib
    • 圧縮率と速度のバランスが良いが, 今では旧い, zstandardを代わりに使うべき
    • checksumは必ず計算する
  • ZStandard
    • 圧縮率と速度のバランスが良い
    • checksumはオプション
  • LZ4
    • 圧縮・伸張速度に重点を置いたもの
      • LZSSだけなので上記2つより圧縮率は低い
    • 圧縮に時間をかけても, 伸張速度はほとんど変わらない
    • checksumはオプション
  • Lizard
    • LZ5を名乗る, LZ4を改良したと主張している

PakのLZ4圧縮

FCompressionを書き換えることは影響範囲を考えてやりたくないです. エンジンのプラグインを書きます. UnrealPakは独立したプログラムのため, 単純なエディタ拡張ではUnrealPakから見えません.

LZ4CompressionFormat.cpp
  1. #include "LZ4Compression.h"
  2. #include "CoreMinimal.h"
  3. #include "Misc/Compression.h"
  4. #include "Misc/ICompressionFormat.h"
  5. #define LOCTEXT_NAMESPACE "FLZ4CompressionModule"
  6. namespace
  7. {
  8. DEFINE_LOG_CATEGORY_STATIC(LogLZ4CompressionFormat, Log, All);
  9. struct LZ4CompressionFormat : public ICompressionFormat
  10. {
  11. FName GetCompressionFormatName() override;
  12. bool Compress(void* CompressedBuffer, int32& CompressedSize, const void* UncompressedBuffer, int32 UncompressedSize, int32 CompressionData) override;
  13. bool Uncompress(void* UncompressedBuffer, int32& UncompressedSize, const void* CompressedBuffer, int32 CompressedSize, int32 CompressionData) override;
  14. int32 GetCompressedBufferSize(int32 UncompressedSize, int32 CompressionData) override;
  15. uint32 GetVersion() override;
  16. FString GetDDCKeySuffix() override;
  17. };
  18. FName LZ4CompressionFormat::GetCompressionFormatName()
  19. {
  20. return "lz4";
  21. }
  22. bool LZ4CompressionFormat::Compress(void* CompressedBuffer, int32& CompressedSize, const void* UncompressedBuffer, int32 UncompressedSize, int32 CompressionData)
  23. {
  24. UE_LOG(LogLZ4CompressionFormat, Warning, TEXT("Compress"));
  25. if(!FCompression::CompressMemory(NAME_LZ4, CompressedBuffer, CompressedSize, UncompressedBuffer, UncompressedSize, COMPRESS_NoFlags, CompressionData)) {
  26. UE_LOG(LogLZ4CompressionFormat, Warning, TEXT("Faile to compress"));
  27. return false;
  28. }
  29. return true;
  30. }
  31. bool LZ4CompressionFormat::Uncompress(void* UncompressedBuffer, int32& UncompressedSize, const void* CompressedBuffer, int32 CompressedSize, int32 CompressionData)
  32. {
  33. UE_LOG(LogLZ4CompressionFormat, Warning, TEXT("Uncompress"));
  34. if(!FCompression::UncompressMemory(NAME_LZ4, UncompressedBuffer, UncompressedSize, CompressedBuffer, CompressedSize, COMPRESS_NoFlags, CompressionData)) {
  35. UE_LOG(LogLZ4CompressionFormat, Warning, TEXT("Faile to uncompress"));
  36. return false;
  37. }
  38. return true;
  39. }
  40. int32 LZ4CompressionFormat::GetCompressedBufferSize(int32 UncompressedSize, int32 CompressionData)
  41. {
  42. return FCompression::CompressMemoryBound(NAME_LZ4, UncompressedSize, COMPRESS_NoFlags, CompressionData);
  43. }
  44. uint32 LZ4CompressionFormat::GetVersion()
  45. {
  46. return FCompression::GetCompressorVersion(NAME_LZ4);
  47. }
  48. FString LZ4CompressionFormat::GetDDCKeySuffix()
  49. {
  50. static const FString suffix = "2AEE7CBB0BD24E71B0D516ECE2AB68C1";
  51. return suffix;
  52. }
  53. } // namespace
  54. FLZ4CompressionModule::FLZ4CompressionModule()
  55. : compressionFormat_(nullptr)
  56. {
  57. }
  58. FLZ4CompressionModule::~FLZ4CompressionModule()
  59. {
  60. delete compressionFormat_;
  61. }
  62. void FLZ4CompressionModule::StartupModule()
  63. {
  64. compressionFormat_ = new LZ4CompressionFormat();
  65. IModularFeatures::Get().RegisterModularFeature(COMPRESSION_FORMAT_FEATURE_NAME, compressionFormat_);
  66. }
  67. void FLZ4CompressionModule::ShutdownModule()
  68. {
  69. IModularFeatures::Get().UnregisterModularFeature(COMPRESSION_FORMAT_FEATURE_NAME, compressionFormat_);
  70. delete compressionFormat_;
  71. compressionFormat_ = nullptr;
  72. }
  73. #undef LOCTEXT_NAMESPACE
  74. IMPLEMENT_MODULE(FLZ4CompressionModule, LZ4Compression)

まとめ

今回は, Pak File Compression Format(s)lz4を書けばLZ4圧縮になるはずです. これを応用すれば好きなフォーマットにできるはずです.

0 件のコメント:

コメントを投稿