diff --git a/libmatroska2/CMakeLists.txt b/libmatroska2/CMakeLists.txt index a0384df4..61f3ff10 100644 --- a/libmatroska2/CMakeLists.txt +++ b/libmatroska2/CMakeLists.txt @@ -3,6 +3,7 @@ project("matroska2" VERSION 0.22.3 LANGUAGES C) option(CONFIG_ZLIB "Enable zlib (de)compression" ON) option(CONFIG_BZLIB "Enable bzlib decompression in libmatroska2" ON) option(CONFIG_LZO1X "Enable lzo decompression in libmatroska2" ON) +option(CONFIG_ZSTD "Enable Zstandard/zstd (de)compression in libmatroska2" ON) option(CONFIG_CODEC_HELPER "Enable Vorbis frame durations in libmatroska2" ON) if (CONFIG_ZLIB) @@ -26,6 +27,30 @@ if (CONFIG_ZLIB) endif() endif() +if (CONFIG_ZSTD) + # find_package(Zstd) + + # if(NOT Zstd_FOUND) + include(FetchContent) + + set(ZSTD_BUILD_STATIC ON) + set(ZSTD_BUILD_SHARED OFF) + set(ZSTD_BUILD_PROGRAMS OFF) + set(ZSTD_BUILD_TESTS OFF) + set(ZSTD_LEGACY_SUPPORT OFF) + + FetchContent_Declare( + zstd + URL "https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz" + URL_HASH SHA256=eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + SOURCE_SUBDIR build/cmake + ) + + FetchContent_MakeAvailable(zstd) + # endif() +endif(CONFIG_ZSTD) + set(matroska2_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/matroskamain.c ${CMAKE_CURRENT_SOURCE_DIR}/matroskablock.c @@ -76,6 +101,11 @@ if (CONFIG_BZLIB) endif() endif(CONFIG_BZLIB) +if (CONFIG_ZSTD) + target_include_directories("matroska2" PRIVATE ${zstd_SOURCE_DIR}/lib) + target_link_libraries("matroska2" PRIVATE $) +endif(CONFIG_ZSTD) + if (CONFIG_CODEC_HELPER) add_subdirectory("tremor") target_link_libraries("matroska2" PRIVATE $) diff --git a/libmatroska2/matroska2/matroska.h b/libmatroska2/matroska2/matroska.h index 2178c802..9de4bac7 100644 --- a/libmatroska2/matroska2/matroska.h +++ b/libmatroska2/matroska2/matroska.h @@ -107,6 +107,14 @@ static INLINE err_t CompressFrameZLib(const uint8_t * UNUSED_PARAM(Cursor), size return ERR_NOT_SUPPORTED; } #endif // !CONFIG_ZLIB +#if defined(CONFIG_ZSTD) +MATROSKA_DLL err_t CompressFrameZstd(const uint8_t *Cursor, size_t CursorSize, uint8_t **OutBuf, size_t *OutSize); +#else // !CONFIG_ZLIB +static INLINE err_t CompressFrameZstd(const uint8_t * UNUSED_PARAM(Cursor), size_t UNUSED_PARAM(CursorSize), uint8_t ** UNUSED_PARAM(OutBuf), size_t * UNUSED_PARAM(OutSize)) +{ + return ERR_NOT_SUPPORTED; +} +#endif // !CONFIG_ZLIB #endif MATROSKA_DLL void MATROSKA_ClusterSort(matroska_cluster *Cluster); // not good with P frames!!! diff --git a/libmatroska2/matroska2/matroska_sem.h b/libmatroska2/matroska2/matroska_sem.h index c2100a37..90e0c719 100644 --- a/libmatroska2/matroska2/matroska_sem.h +++ b/libmatroska2/matroska2/matroska_sem.h @@ -343,6 +343,7 @@ typedef enum { MATROSKA_TRACK_ENCODING_COMP_BZLIB = 1, // bzip2 compression (BZIP2) **SHOULD NOT** be used. MATROSKA_TRACK_ENCODING_COMP_LZO1X = 2, // Lempel-Ziv-Oberhumer compression (LZO) **SHOULD NOT** be used. MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP = 3, // Octets in ContentCompSettings ((#contentcompsettings-element)) have been stripped from each frame. + MATROSKA_TRACK_ENCODING_COMP_ZSTD = 4, // Zstandard (zstd). } MatroskaTrackEncodingCompAlgo; /** diff --git a/libmatroska2/matroska_config.h.in b/libmatroska2/matroska_config.h.in index ccf1fa25..d101e0dd 100644 --- a/libmatroska2/matroska_config.h.in +++ b/libmatroska2/matroska_config.h.in @@ -2,6 +2,7 @@ #cmakedefine CONFIG_ZLIB #cmakedefine CONFIG_LZO1X #cmakedefine CONFIG_BZLIB +#cmakedefine CONFIG_ZSTD #cmakedefine CONFIG_CODEC_HELPER #define LIBMATROSKA2_PROJECT_VERSION T("@matroska2_VERSION_MAJOR@.@matroska2_VERSION_MINOR@.@matroska2_VERSION_PATCH@") diff --git a/libmatroska2/matroskamain.c b/libmatroska2/matroskamain.c index 0bfd7fb5..79cbe190 100644 --- a/libmatroska2/matroskamain.c +++ b/libmatroska2/matroskamain.c @@ -15,6 +15,9 @@ #if defined(CONFIG_LZO1X) #include "minilzo.h" #endif +#if defined(CONFIG_ZSTD) +#include +#endif #include #include #include @@ -225,6 +228,94 @@ err_t CompressFrameZLib(const uint8_t *Cursor, size_t CursorSize, uint8_t **OutB #endif // CONFIG_EBML_WRITING #endif // CONFIG_ZLIB +#if defined(CONFIG_ZSTD) +err_t UnCompressFrameZstd(const uint8_t *Cursor, size_t CursorSize, array *OutBuf, size_t *FrameSize, size_t *ArrayOffset) +{ + uint8_t Buffer[4+14]; // 14: max frame header size + STORE32LE(Buffer, ZSTD_MAGICNUMBER); + memcpy(&Buffer[4], Cursor, MIN(sizeof(Buffer)-4, CursorSize)); + + unsigned long long outSize = ZSTD_getFrameContentSize(Buffer, sizeof(Buffer)); + if (ZSTD_isError(outSize)) + return ERR_INVALID_DATA; + if (!ArrayResize(OutBuf, outSize + *ArrayOffset, 0)) + return ERR_OUT_OF_MEMORY; + + err_t Err = ERR_NONE; + ZSTD_DStream *dstream = ZSTD_createDStream(); + if (dstream == NULL) + return ERR_OUT_OF_MEMORY; + size_t Count; + Count = ZSTD_initDStream(dstream); + if (ZSTD_isError(Count)) + Err = ERR_INVALID_DATA; + else + { + ZSTD_inBuffer in; + ZSTD_outBuffer out; + out.dst = ARRAYBEGIN(*OutBuf,uint8_t) + *ArrayOffset; + out.size = ARRAYCOUNT(*OutBuf,uint8_t) - *ArrayOffset; + out.pos = 0; + + // feed the header + in.src = Buffer; + in.size = 4; + in.pos = 0; + Count = ZSTD_decompressStream(dstream, &out, &in); + if (ZSTD_isError(Count)) + Err = ERR_INVALID_DATA; + else + { + // feed the data + in.src = Cursor; + in.size = CursorSize; + in.pos = 0; + Count = ZSTD_decompressStream(dstream, &out, &in); + if (ZSTD_isError(Count)) + Err = ERR_INVALID_DATA; + else + *FrameSize = out.size + *ArrayOffset; + } + } + ZSTD_freeDStream(dstream); + return Err; +} + +#if defined(CONFIG_EBML_WRITING) +err_t CompressFrameZstd(const uint8_t *Cursor, size_t CursorSize, uint8_t **OutBuf, size_t *OutSize) +{ + ZSTD_CCtx* cctx = ZSTD_createCCtx(); + if (cctx == NULL) + return ERR_OUT_OF_MEMORY; + void *output; + if (OutBuf) + output = *OutBuf; + else + { + output = malloc(CursorSize + 14); // extra header in case the compression is bad + if (output == NULL) + { + ZSTD_freeCCtx(cctx); + return ERR_OUT_OF_MEMORY; + } + *OutSize += 14; + } + size_t result = ZSTD_compressCCtx(cctx, output, *OutSize, Cursor, CursorSize, ZSTD_CLEVEL_DEFAULT); + ZSTD_freeCCtx(cctx); + assert(ZSTD_isError(result) || *((fourcc_t*)output) == ZSTD_MAGICNUMBER); + if (!OutBuf) + free(output); + if (ZSTD_isError(result)) + return ERR_WRITE; + // strip the magic number + if (OutBuf) + *OutBuf = *OutBuf + 4; + *OutSize = result - 4; + return ERR_NONE; +} +#endif // CONFIG_EBML_WRITING +#endif // CONFIG_ZSTD + static err_t CheckCompression(matroska_block *Block, int ForProfile) { ebml_master *Elt, *Header; @@ -261,6 +352,10 @@ static err_t CheckCompression(matroska_block *Block, int ForProfile) #if defined(CONFIG_BZLIB) else if (CompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_BZLIB) CanDecompress = 1; +#endif +#if defined(CONFIG_ZSTD) + else if (CompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_ZSTD) + CanDecompress = 1; #endif if (!CanDecompress) return ERR_INVALID_DATA; @@ -1017,6 +1112,10 @@ err_t MATROSKA_BlockReadData(matroska_block *Element, struct stream *Input, int #if defined(CONFIG_BZLIB) else if (CompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_BZLIB) CanDecompress = 1; +#endif +#if defined(CONFIG_ZSTD) + else if (CompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_ZSTD) + CanDecompress = 1; #endif if (!CanDecompress) return ERR_INVALID_DATA; @@ -1026,7 +1125,7 @@ err_t MATROSKA_BlockReadData(matroska_block *Element, struct stream *Input, int } } -#if !defined(CONFIG_ZLIB) && !defined(CONFIG_LZO1X) && !defined(CONFIG_BZLIB) +#if !defined(CONFIG_ZLIB) && !defined(CONFIG_LZO1X) && !defined(CONFIG_BZLIB) && !defined(CONFIG_ZSTD) if (Header && Header->Context==MATROSKA_getContextContentCompAlgo()) return ERR_NOT_SUPPORTED; #endif @@ -1040,7 +1139,7 @@ err_t MATROSKA_BlockReadData(matroska_block *Element, struct stream *Input, int switch (Element->Lacing) { case LACING_NONE: -#if defined(CONFIG_ZLIB) || defined(CONFIG_LZO1X) || defined(CONFIG_BZLIB) +#if defined(CONFIG_ZLIB) || defined(CONFIG_LZO1X) || defined(CONFIG_BZLIB) || defined(CONFIG_ZSTD) if (Header && Header->Context==MATROSKA_getContextContentCompAlgo()) { // zlib handling, read the buffer in temp memory @@ -1069,6 +1168,19 @@ err_t MATROSKA_BlockReadData(matroska_block *Element, struct stream *Input, int } } #endif +#if defined(CONFIG_ZSTD) + if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_TRACK_ENCODING_COMP_ZSTD) + { + size_t UncompressedSize; + size_t Offset = 0; + Err = UnCompressFrameZstd(InBuf, ARRAYBEGIN(Element->SizeList,int32_t)[0], &Element->Data, &UncompressedSize, &Offset); + if (Err == ERR_NONE) + { + ArrayResize(&Element->Data, UncompressedSize, 0); + ARRAYBEGIN(Element->SizeList,int32_t)[0] = UncompressedSize; + } + } +#endif #if defined(CONFIG_LZO1X) if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_TRACK_ENCODING_COMP_LZO1X) { @@ -1173,7 +1285,7 @@ err_t MATROSKA_BlockReadData(matroska_block *Element, struct stream *Input, int BufSize = 0; for (NumFrame=0;NumFrameSizeList,int32_t);++NumFrame) BufSize += ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame]; -#if defined(CONFIG_ZLIB) || defined(CONFIG_LZO1X) || defined(CONFIG_BZLIB) +#if defined(CONFIG_ZLIB) || defined(CONFIG_LZO1X) || defined(CONFIG_BZLIB) || defined(CONFIG_ZSTD) if (Header && Header->Context==MATROSKA_getContextContentCompAlgo()) { // zlib handling, read the buffer in temp memory @@ -1213,6 +1325,18 @@ err_t MATROSKA_BlockReadData(matroska_block *Element, struct stream *Input, int } } #endif +#if defined(CONFIG_ZSTD) + if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_TRACK_ENCODING_COMP_ZSTD) + { + size_t UncompressedSize; + Err = UnCompressFrameZstd(InBuf, FrameSize, &Element->Data, &UncompressedSize, &Offset); + if (Err == ERR_NONE) + { + OutSize += UncompressedSize; + ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame] = UncompressedSize; + } + } +#endif #if defined(CONFIG_LZO1X) if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_TRACK_ENCODING_COMP_LZO1X) { @@ -1602,6 +1726,10 @@ static filepos_t GetBlockFrameSize(const matroska_block *Element, size_t Frame, if (CompAlgo == MATROSKA_TRACK_ENCODING_COMP_ZLIB && CompressFrameZLib(Data,ARRAYBEGIN(Element->SizeList,int32_t)[Frame],NULL,&OutSize)!=ERR_NONE) return ARRAYBEGIN(Element->SizeList,int32_t)[Frame]; // we can't tell the final size without decoding the data #endif +#if defined(CONFIG_ZSTD) + if (CompAlgo == MATROSKA_TRACK_ENCODING_COMP_ZSTD && CompressFrameZstd(Data,ARRAYBEGIN(Element->SizeList,int32_t)[Frame],NULL,&OutSize)!=ERR_NONE) + return ARRAYBEGIN(Element->SizeList,int32_t)[Frame]; // we can't tell the final size without decoding the data +#endif #endif return OutSize; } @@ -1658,6 +1786,10 @@ static char GetBestLacingType(const matroska_block *Element, int ForProfile) #if defined(CONFIG_ZLIB) else if (CompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_ZLIB) CanCompress = 1; +#endif +#if defined(CONFIG_ZSTD) + else if (CompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_ZSTD) + CanCompress = 1; #endif if (!CanCompress) return 0; @@ -1770,6 +1902,10 @@ static err_t RenderBlockData(matroska_block *Element, struct stream *Output, boo #if defined(CONFIG_ZLIB) else if (CompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_ZLIB) CanCompress = 1; +#endif +#if defined(CONFIG_ZSTD) + else if (CompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_ZSTD) + CanCompress = 1; #endif if (!CanCompress) { @@ -1880,6 +2016,39 @@ static err_t RenderBlockData(matroska_block *Element, struct stream *Output, boo } } #endif +#if defined(CONFIG_ZSTD) + if (CompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_ZSTD) + { + uint8_t *OutBuf; + array TmpBuf; + ArrayInit(&TmpBuf); + for (i=ARRAYBEGIN(Element->SizeList,int32_t);i!=ARRAYEND(Element->SizeList,int32_t);++i) + { + if (!ArrayResize(&TmpBuf,*i + 100,0)) + { + ArrayClear(&TmpBuf); + Err = ERR_OUT_OF_MEMORY; + break; + } + OutBuf = ARRAYBEGIN(TmpBuf,uint8_t); + ToWrite = ARRAYCOUNT(TmpBuf,uint8_t); + if (CompressFrameZstd(Cursor, *i, &OutBuf, &ToWrite) != ERR_NONE) + { + ArrayClear(&TmpBuf); + Err = ERR_OUT_OF_MEMORY; + break; + } + + Err = Stream_Write(Output,OutBuf,ToWrite,&Written); + ArrayClear(&TmpBuf); + if (Rendered) + *Rendered += Written; + Cursor += *i; + if (Err!=ERR_NONE) + break; + } + } +#endif } else { @@ -1984,6 +2153,10 @@ static filepos_t UpdateBlockSize(matroska_block *Element, bool_t bWithDefault, b #if defined(CONFIG_ZLIB) else if (CompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_ZLIB) CanCompress = 1; +#endif +#if defined(CONFIG_ZSTD) + else if (CompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_ZSTD) + CanCompress = 1; #endif if (!CanCompress) return ERR_INVALID_DATA; @@ -2291,6 +2464,14 @@ static filepos_t UpdateDataSizeTrackEntry(matroska_trackentry *Element, bool_t b if (EBML_BinarySetData(CodecPrivate, NewCompressed, CompressedSize)==ERR_NONE) Element->CodecPrivateCompressionAlgo = MATROSKA_TRACK_ENCODING_COMP_ZLIB; } +#endif +#if defined(CONFIG_ZSTD) + if (CompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_ZSTD && + CompressFrameZstd(ARRAYBEGIN(CodecPrivate->Data,uint8_t), (size_t)CodecPrivate->Base.DataSize, &NewCompressed, &CompressedSize)==ERR_NONE) + { + if (EBML_BinarySetData(CodecPrivate, NewCompressed, CompressedSize)==ERR_NONE) + Element->CodecPrivateCompressionAlgo = MATROSKA_TRACK_ENCODING_COMP_ZSTD; + } #endif free(Compressed); } @@ -2313,6 +2494,14 @@ static filepos_t UpdateDataSizeTrackEntry(matroska_trackentry *Element, bool_t b if (EBML_BinarySetData(CodecPrivate, ARRAYBEGIN(Compressed,uint8_t), CompressedSize)==ERR_NONE) Element->CodecPrivateCompressionAlgo = MATROSKA_TRACK_ENCODING_COMP_NONE; } +#endif +#if defined(CONFIG_ZSTD) + if (Element->CodecPrivateCompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_ZSTD && + UnCompressFrameZstd(ARRAYBEGIN(CodecPrivate->Data,uint8_t), (size_t)CodecPrivate->Base.DataSize, &Compressed, &CompressedSize, &Offset)==ERR_NONE) + { + if (EBML_BinarySetData(CodecPrivate, ARRAYBEGIN(Compressed,uint8_t), CompressedSize)==ERR_NONE) + Element->CodecPrivateCompressionAlgo = MATROSKA_TRACK_ENCODING_COMP_NONE; + } #endif ArrayClear(&Compressed); } @@ -2358,10 +2547,12 @@ MatroskaTrackEncodingCompAlgo MATROSKA_TrackGetBlockCompression(const matroska_t bool_t MATROSKA_TrackSetCompressionAlgo(matroska_trackentry *TrackEntry, MatroskaContentEncodingScope Scope, int ForProfile, MatroskaTrackEncodingCompAlgo algo) { - // force zlib compression + // force zlib or Zstd compression bool_t HadEncoding; ebml_element *Encodings, *Elt, *Elt2; assert(Node_IsPartOf(TrackEntry, MATROSKA_TRACKENTRY_CLASS)); + if (Scope != 0 && algo != MATROSKA_TRACK_ENCODING_COMP_ZLIB && algo != MATROSKA_TRACK_ENCODING_COMP_ZSTD) + return 0; // remove the previous compression and the new optimized one Encodings = EBML_MasterFindChild(TrackEntry,MATROSKA_getContextContentEncodings()); HadEncoding = Encodings!=NULL; diff --git a/mkclean/mkclean.c b/mkclean/mkclean.c index 681304ee..593d06c3 100644 --- a/mkclean/mkclean.c +++ b/mkclean/mkclean.c @@ -1424,7 +1424,7 @@ static bool_t BlockIsCompressed(const matroska_block *Block) return 1; // we don't support encryption Elt = (ebml_master*)EBML_MasterGetChild(Elt, MATROSKA_getContextContentCompAlgo(), DstProfile); - if (Elt!=NULL && EBML_IntegerValue((ebml_integer*)Elt)==MATROSKA_TRACK_ENCODING_COMP_ZLIB) + if (Elt!=NULL && (EBML_IntegerValue((ebml_integer*)Elt)!=MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP)) return 1; } } @@ -1517,6 +1517,7 @@ int main(int argc, const char *argv[]) mkv_timestamp_t PrevTimestamp; bool_t CuesChanged; bool_t KeepCues = 0, Remux = 0, CuesCreated = 0, Optimize = 0, OptimizeVideo = 1, UnOptimize = 0, ClustersNeedRead = 0, Regression = 0; + MatroskaTrackEncodingCompAlgo CompressionAlgo = MATROSKA_TRACK_ENCODING_COMP_NONE; int InputPathIndex = 1; int64_t TimestampScale = 0, OldTimestampScale; size_t MaxTrackNum = 0; @@ -1623,6 +1624,26 @@ int main(int argc, const char *argv[]) else if (tcsisame_ascii(Path,T("--unsafe"))) { Unsafe = 1; InputPathIndex = i+1; } else if (tcsisame_ascii(Path,T("--optimize"))) { Optimize = 1; OptimizeVideo = 1; InputPathIndex = i+1; } else if (tcsisame_ascii(Path,T("--optimize_nv"))) { Optimize = 1; OptimizeVideo = 0; InputPathIndex = i+1; } + else if (tcsisame_ascii(Path,T("--compalgo")) && i+1 force the global TimestampScale to (1000000 is a good value)\r\n")); TextWrite(StdErr,T(" --unsafe don't output elements that are used for file recovery (saves more space)\r\n")); + TextWrite(StdErr,T(" --compalgo force compression algorithm of all tracks\r\n")); TextWrite(StdErr,T(" --optimize use all possible optimization for the output file\r\n")); TextWrite(StdErr,T(" --optimize_nv use all possible optimization for the output file, except video tracks\r\n")); TextWrite(StdErr,T(" --no-optimize disable some optimization for the output file\r\n")); @@ -2772,7 +2794,9 @@ int main(int argc, const char *argv[]) { Elt = EBML_MasterFindFirstElt(RLevel1,MATROSKA_getContextCodecID(),1,0,0); EBML_StringGet((ebml_string*)Elt,CodecID,TSIZEOF(CodecID)); - if (tcsisame_ascii(CodecID,T("S_USF")) || tcsisame_ascii(CodecID,T("S_VOBSUB")) || tcsisame_ascii(CodecID,T("S_HDMV/PGS")) || tcsisame_ascii(CodecID,T("B_VOBBTN")) + if (CompressionAlgo != MATROSKA_TRACK_ENCODING_COMP_NONE) + encoding = CompressionAlgo; + else if (tcsisame_ascii(CodecID,T("S_USF")) || tcsisame_ascii(CodecID,T("S_VOBSUB")) || tcsisame_ascii(CodecID,T("S_HDMV/PGS")) || tcsisame_ascii(CodecID,T("B_VOBBTN")) || tcsisame_ascii(CodecID,T("V_UNCOMPRESSED"))|| tcsstr(CodecID,T("A_PCM"))==CodecID) encoding = MATROSKA_TRACK_ENCODING_COMP_ZLIB; else @@ -2809,13 +2833,24 @@ int main(int argc, const char *argv[]) if (CodecPrivate!=NULL) { size_t ExtraCompHeaderBytes = (encoding == MATROSKA_TRACK_ENCODING_COMP_NONE) ? 13 : 3; // extra bytes needed to add the comp header to the track + if (CompressionAlgo != MATROSKA_TRACK_ENCODING_COMP_ZLIB) + ExtraCompHeaderBytes += 1; // extra for the non default algo size_t CompressedSize = (size_t)EBML_ElementDataSize((ebml_element*)CodecPrivate, 1); size_t origCompressedSize = CompressedSize; uint8_t *Compressed = malloc(CompressedSize); - if (CompressFrameZLib(EBML_BinaryGetData(CodecPrivate), origCompressedSize, &Compressed, &CompressedSize)==ERR_NONE - && (CompressedSize + ExtraCompHeaderBytes) < origCompressedSize) + uint8_t *NewCompressed = Compressed; + int comp_err; + if (CompressionAlgo == MATROSKA_TRACK_ENCODING_COMP_ZSTD) + { + comp_err = CompressFrameZstd(EBML_BinaryGetData(CodecPrivate), origCompressedSize, &NewCompressed, &CompressedSize); + } + else { - encoding = MATROSKA_TRACK_ENCODING_COMP_ZLIB; + comp_err = CompressFrameZLib(EBML_BinaryGetData(CodecPrivate), origCompressedSize, &NewCompressed, &CompressedSize); + } + if (comp_err==ERR_NONE && (CompressedSize + ExtraCompHeaderBytes) < origCompressedSize) + { + encoding = CompressionAlgo; compress_scope |= MATROSKA_CONTENTENCODINGSCOPE_PRIVATE; } free(Compressed); @@ -2830,6 +2865,12 @@ int main(int argc, const char *argv[]) if (MATROSKA_TrackSetCompressionAlgo((matroska_trackentry*)RLevel1, compress_scope,DstProfile, MATROSKA_TRACK_ENCODING_COMP_ZLIB)) ClustersNeedRead = 1; break; +#if defined(CONFIG_ZSTD) + case MATROSKA_TRACK_ENCODING_COMP_ZSTD: + if (MATROSKA_TrackSetCompressionAlgo((matroska_trackentry*)RLevel1, compress_scope,DstProfile, MATROSKA_TRACK_ENCODING_COMP_ZSTD)) + ClustersNeedRead = 1; + break; +#endif case MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP: if (!HeaderData || MATROSKA_TrackSetCompressionHeader((matroska_trackentry*)RLevel1, ARRAYBEGIN(*HeaderData,uint8_t), ARRAYCOUNT(*HeaderData,uint8_t), DstProfile)) ClustersNeedRead = 1;