chdman/3rdparty/lzma/CPP/7zip/Archive/Common/CoderMixer2.cpp
2022-01-05 08:45:19 +02:00

1045 lines
24 KiB
C++

// CoderMixer2.cpp
#include "StdAfx.h"
#include "CoderMixer2.h"
#ifdef USE_MIXER_ST
STDMETHODIMP CSequentialInStreamCalcSize::Read(void *data, UInt32 size, UInt32 *processedSize)
{
UInt32 realProcessed = 0;
HRESULT result = S_OK;
if (_stream)
result = _stream->Read(data, size, &realProcessed);
_size += realProcessed;
if (size != 0 && realProcessed == 0)
_wasFinished = true;
if (processedSize)
*processedSize = realProcessed;
return result;
}
STDMETHODIMP COutStreamCalcSize::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
HRESULT result = S_OK;
if (_stream)
result = _stream->Write(data, size, &size);
_size += size;
if (processedSize)
*processedSize = size;
return result;
}
STDMETHODIMP COutStreamCalcSize::OutStreamFinish()
{
HRESULT result = S_OK;
if (_stream)
{
CMyComPtr<IOutStreamFinish> outStreamFinish;
_stream.QueryInterface(IID_IOutStreamFinish, &outStreamFinish);
if (outStreamFinish)
result = outStreamFinish->OutStreamFinish();
}
return result;
}
#endif
namespace NCoderMixer2 {
static void BoolVector_Fill_False(CBoolVector &v, unsigned size)
{
v.ClearAndSetSize(size);
bool *p = &v[0];
for (unsigned i = 0; i < size; i++)
p[i] = false;
}
class CBondsChecks
{
CBoolVector _coderUsed;
bool Init();
bool CheckCoder(unsigned coderIndex);
public:
const CBindInfo *BindInfo;
bool Check();
};
bool CBondsChecks::CheckCoder(unsigned coderIndex)
{
const CCoderStreamsInfo &coder = BindInfo->Coders[coderIndex];
if (coderIndex >= _coderUsed.Size() || _coderUsed[coderIndex])
return false;
_coderUsed[coderIndex] = true;
UInt32 start = BindInfo->Coder_to_Stream[coderIndex];
for (unsigned i = 0; i < coder.NumStreams; i++)
{
UInt32 ind = start + i;
if (BindInfo->IsStream_in_PackStreams(ind))
continue;
int bond = BindInfo->FindBond_for_PackStream(ind);
if (bond < 0)
return false;
if (!CheckCoder(BindInfo->Bonds[bond].UnpackIndex))
return false;
}
return true;
}
bool CBondsChecks::Check()
{
BoolVector_Fill_False(_coderUsed, BindInfo->Coders.Size());
if (!CheckCoder(BindInfo->UnpackCoder))
return false;
FOR_VECTOR(i, _coderUsed)
if (!_coderUsed[i])
return false;
return true;
}
void CBindInfo::ClearMaps()
{
Coder_to_Stream.Clear();
Stream_to_Coder.Clear();
}
bool CBindInfo::CalcMapsAndCheck()
{
ClearMaps();
UInt32 numStreams = 0;
if (Coders.Size() == 0)
return false;
if (Coders.Size() - 1 != Bonds.Size())
return false;
FOR_VECTOR(i, Coders)
{
Coder_to_Stream.Add(numStreams);
const CCoderStreamsInfo &c = Coders[i];
for (unsigned j = 0; j < c.NumStreams; j++)
Stream_to_Coder.Add(i);
numStreams += c.NumStreams;
}
if (numStreams != GetNum_Bonds_and_PackStreams())
return false;
CBondsChecks bc;
bc.BindInfo = this;
return bc.Check();
}
void CCoder::SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes)
{
if (unpackSize)
{
UnpackSize = *unpackSize;
UnpackSizePointer = &UnpackSize;
}
else
{
UnpackSize = 0;
UnpackSizePointer = NULL;
}
PackSizes.ClearAndSetSize((unsigned)NumStreams);
PackSizePointers.ClearAndSetSize((unsigned)NumStreams);
for (unsigned i = 0; i < NumStreams; i++)
{
if (packSizes && packSizes[i])
{
PackSizes[i] = *(packSizes[i]);
PackSizePointers[i] = &PackSizes[i];
}
else
{
PackSizes[i] = 0;
PackSizePointers[i] = NULL;
}
}
}
bool CMixer::Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex)
{
if (coderIndex == _bi.UnpackCoder)
return true;
int bond = _bi.FindBond_for_UnpackStream(coderIndex);
if (bond < 0)
throw 20150213;
/*
UInt32 coderIndex, coderStreamIndex;
_bi.GetCoder_for_Stream(_bi.Bonds[bond].PackIndex, coderIndex, coderStreamIndex);
*/
UInt32 nextCoder = _bi.Stream_to_Coder[_bi.Bonds[bond].PackIndex];
if (!IsFilter_Vector[nextCoder])
return false;
return Is_UnpackSize_Correct_for_Coder(nextCoder);
}
bool CMixer::Is_PackSize_Correct_for_Stream(UInt32 streamIndex)
{
if (_bi.IsStream_in_PackStreams(streamIndex))
return true;
int bond = _bi.FindBond_for_PackStream(streamIndex);
if (bond < 0)
throw 20150213;
UInt32 nextCoder = _bi.Bonds[bond].UnpackIndex;
if (!IsFilter_Vector[nextCoder])
return false;
return Is_PackSize_Correct_for_Coder(nextCoder);
}
bool CMixer::Is_PackSize_Correct_for_Coder(UInt32 coderIndex)
{
UInt32 startIndex = _bi.Coder_to_Stream[coderIndex];
UInt32 numStreams = _bi.Coders[coderIndex].NumStreams;
for (UInt32 i = 0; i < numStreams; i++)
if (!Is_PackSize_Correct_for_Stream(startIndex + i))
return false;
return true;
}
bool CMixer::IsThere_ExternalCoder_in_PackTree(UInt32 coderIndex)
{
if (IsExternal_Vector[coderIndex])
return true;
UInt32 startIndex = _bi.Coder_to_Stream[coderIndex];
UInt32 numStreams = _bi.Coders[coderIndex].NumStreams;
for (UInt32 i = 0; i < numStreams; i++)
{
UInt32 si = startIndex + i;
if (_bi.IsStream_in_PackStreams(si))
continue;
int bond = _bi.FindBond_for_PackStream(si);
if (bond < 0)
throw 20150213;
if (IsThere_ExternalCoder_in_PackTree(_bi.Bonds[bond].UnpackIndex))
return true;
}
return false;
}
#ifdef USE_MIXER_ST
CMixerST::CMixerST(bool encodeMode):
CMixer(encodeMode)
{}
CMixerST::~CMixerST() {}
void CMixerST::AddCoder(const CCreatedCoder &cod)
{
IsFilter_Vector.Add(cod.IsFilter);
IsExternal_Vector.Add(cod.IsExternal);
// const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()];
CCoderST &c2 = _coders.AddNew();
c2.NumStreams = cod.NumStreams;
c2.Coder = cod.Coder;
c2.Coder2 = cod.Coder2;
/*
if (isFilter)
{
c2.CanRead = true;
c2.CanWrite = true;
}
else
*/
{
IUnknown *unk = (cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2);
{
CMyComPtr<ISequentialInStream> s;
unk->QueryInterface(IID_ISequentialInStream, (void**)&s);
c2.CanRead = (s != NULL);
}
{
CMyComPtr<ISequentialOutStream> s;
unk->QueryInterface(IID_ISequentialOutStream, (void**)&s);
c2.CanWrite = (s != NULL);
}
}
}
CCoder &CMixerST::GetCoder(unsigned index)
{
return _coders[index];
}
void CMixerST::ReInit() {}
HRESULT CMixerST::GetInStream2(
ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
UInt32 outStreamIndex, ISequentialInStream **inStreamRes)
{
UInt32 coderIndex = outStreamIndex, coderStreamIndex = 0;
if (EncodeMode)
{
_bi.GetCoder_for_Stream(outStreamIndex, coderIndex, coderStreamIndex);
if (coderStreamIndex != 0)
return E_NOTIMPL;
}
const CCoder &coder = _coders[coderIndex];
CMyComPtr<ISequentialInStream> seqInStream;
coder.QueryInterface(IID_ISequentialInStream, (void **)&seqInStream);
if (!seqInStream)
return E_NOTIMPL;
UInt32 numInStreams = EncodeMode ? 1 : coder.NumStreams;
UInt32 startIndex = EncodeMode ? coderIndex : _bi.Coder_to_Stream[coderIndex];
bool isSet = false;
if (numInStreams == 1)
{
CMyComPtr<ICompressSetInStream> setStream;
coder.QueryInterface(IID_ICompressSetInStream, (void **)&setStream);
if (setStream)
{
CMyComPtr<ISequentialInStream> seqInStream2;
RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + 0, &seqInStream2));
RINOK(setStream->SetInStream(seqInStream2));
isSet = true;
}
}
if (!isSet && numInStreams != 0)
{
CMyComPtr<ICompressSetInStream2> setStream2;
coder.QueryInterface(IID_ICompressSetInStream2, (void **)&setStream2);
if (!setStream2)
return E_NOTIMPL;
for (UInt32 i = 0; i < numInStreams; i++)
{
CMyComPtr<ISequentialInStream> seqInStream2;
RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + i, &seqInStream2));
RINOK(setStream2->SetInStream2(i, seqInStream2));
}
}
*inStreamRes = seqInStream.Detach();
return S_OK;
}
HRESULT CMixerST::GetInStream(
ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
UInt32 inStreamIndex, ISequentialInStream **inStreamRes)
{
CMyComPtr<ISequentialInStream> seqInStream;
{
int index = -1;
if (EncodeMode)
{
if (_bi.UnpackCoder == inStreamIndex)
index = 0;
}
else
index = _bi.FindStream_in_PackStreams(inStreamIndex);
if (index >= 0)
{
seqInStream = inStreams[(unsigned)index];
*inStreamRes = seqInStream.Detach();
return S_OK;
}
}
int bond = FindBond_for_Stream(
true, // forInputStream
inStreamIndex);
if (bond < 0)
return E_INVALIDARG;
RINOK(GetInStream2(inStreams, /* inSizes, */
_bi.Bonds[bond].Get_OutIndex(EncodeMode), &seqInStream));
while (_binderStreams.Size() <= (unsigned)bond)
_binderStreams.AddNew();
CStBinderStream &bs = _binderStreams[bond];
if (bs.StreamRef || bs.InStreamSpec)
return E_NOTIMPL;
CSequentialInStreamCalcSize *spec = new CSequentialInStreamCalcSize;
bs.StreamRef = spec;
bs.InStreamSpec = spec;
spec->SetStream(seqInStream);
spec->Init();
seqInStream = bs.InStreamSpec;
*inStreamRes = seqInStream.Detach();
return S_OK;
}
HRESULT CMixerST::GetOutStream(
ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */
UInt32 outStreamIndex, ISequentialOutStream **outStreamRes)
{
CMyComPtr<ISequentialOutStream> seqOutStream;
{
int index = -1;
if (!EncodeMode)
{
if (_bi.UnpackCoder == outStreamIndex)
index = 0;
}
else
index = _bi.FindStream_in_PackStreams(outStreamIndex);
if (index >= 0)
{
seqOutStream = outStreams[(unsigned)index];
*outStreamRes = seqOutStream.Detach();
return S_OK;
}
}
int bond = FindBond_for_Stream(
false, // forInputStream
outStreamIndex);
if (bond < 0)
return E_INVALIDARG;
UInt32 inStreamIndex = _bi.Bonds[bond].Get_InIndex(EncodeMode);
UInt32 coderIndex = inStreamIndex;
UInt32 coderStreamIndex = 0;
if (!EncodeMode)
_bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex);
CCoder &coder = _coders[coderIndex];
/*
if (!coder.Coder)
return E_NOTIMPL;
*/
coder.QueryInterface(IID_ISequentialOutStream, (void **)&seqOutStream);
if (!seqOutStream)
return E_NOTIMPL;
UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1;
UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex;
bool isSet = false;
if (numOutStreams == 1)
{
CMyComPtr<ICompressSetOutStream> setOutStream;
coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream);
if (setOutStream)
{
CMyComPtr<ISequentialOutStream> seqOutStream2;
RINOK(GetOutStream(outStreams, /* outSizes, */ startIndex + 0, &seqOutStream2));
RINOK(setOutStream->SetOutStream(seqOutStream2));
isSet = true;
}
}
if (!isSet && numOutStreams != 0)
{
return E_NOTIMPL;
/*
CMyComPtr<ICompressSetOutStream2> setStream2;
coder.QueryInterface(IID_ICompressSetOutStream2, (void **)&setStream2);
if (!setStream2)
return E_NOTIMPL;
for (UInt32 i = 0; i < numOutStreams; i++)
{
CMyComPtr<ISequentialOutStream> seqOutStream2;
RINOK(GetOutStream(outStreams, startIndex + i, &seqOutStream2));
RINOK(setStream2->SetOutStream2(i, seqOutStream2));
}
*/
}
while (_binderStreams.Size() <= (unsigned)bond)
_binderStreams.AddNew();
CStBinderStream &bs = _binderStreams[bond];
if (bs.StreamRef || bs.OutStreamSpec)
return E_NOTIMPL;
COutStreamCalcSize *spec = new COutStreamCalcSize;
bs.StreamRef = (ISequentialOutStream *)spec;
bs.OutStreamSpec = spec;
spec->SetStream(seqOutStream);
spec->Init();
seqOutStream = bs.OutStreamSpec;
*outStreamRes = seqOutStream.Detach();
return S_OK;
}
static HRESULT GetError(HRESULT res, HRESULT res2)
{
if (res == res2)
return res;
if (res == S_OK)
return res2;
if (res == k_My_HRESULT_WritingWasCut)
{
if (res2 != S_OK)
return res2;
}
return res;
}
HRESULT CMixerST::FinishStream(UInt32 streamIndex)
{
{
int index = -1;
if (!EncodeMode)
{
if (_bi.UnpackCoder == streamIndex)
index = 0;
}
else
index = _bi.FindStream_in_PackStreams(streamIndex);
if (index >= 0)
return S_OK;
}
int bond = FindBond_for_Stream(
false, // forInputStream
streamIndex);
if (bond < 0)
return E_INVALIDARG;
UInt32 inStreamIndex = _bi.Bonds[bond].Get_InIndex(EncodeMode);
UInt32 coderIndex = inStreamIndex;
UInt32 coderStreamIndex = 0;
if (!EncodeMode)
_bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex);
CCoder &coder = _coders[coderIndex];
CMyComPtr<IOutStreamFinish> finish;
coder.QueryInterface(IID_IOutStreamFinish, (void **)&finish);
HRESULT res = S_OK;
if (finish)
{
res = finish->OutStreamFinish();
}
return GetError(res, FinishCoder(coderIndex));
}
HRESULT CMixerST::FinishCoder(UInt32 coderIndex)
{
CCoder &coder = _coders[coderIndex];
UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1;
UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex;
HRESULT res = S_OK;
for (unsigned i = 0; i < numOutStreams; i++)
res = GetError(res, FinishStream(startIndex + i));
return res;
}
void CMixerST::SelectMainCoder(bool useFirst)
{
unsigned ci = _bi.UnpackCoder;
int firstNonFilter = -1;
int firstAllowed = ci;
for (;;)
{
const CCoderST &coder = _coders[ci];
// break;
if (ci != _bi.UnpackCoder)
if (EncodeMode ? !coder.CanWrite : !coder.CanRead)
{
firstAllowed = ci;
firstNonFilter = -2;
}
if (coder.NumStreams != 1)
break;
UInt32 st = _bi.Coder_to_Stream[ci];
if (_bi.IsStream_in_PackStreams(st))
break;
int bond = _bi.FindBond_for_PackStream(st);
if (bond < 0)
throw 20150213;
if (EncodeMode ? !coder.CanRead : !coder.CanWrite)
break;
if (firstNonFilter == -1 && !IsFilter_Vector[ci])
firstNonFilter = ci;
ci = _bi.Bonds[bond].UnpackIndex;
}
if (useFirst)
ci = firstAllowed;
else if (firstNonFilter >= 0)
ci = firstNonFilter;
MainCoderIndex = ci;
}
HRESULT CMixerST::Code(
ISequentialInStream * const *inStreams,
ISequentialOutStream * const *outStreams,
ICompressProgressInfo *progress)
{
_binderStreams.Clear();
unsigned ci = MainCoderIndex;
const CCoder &mainCoder = _coders[MainCoderIndex];
CObjectVector< CMyComPtr<ISequentialInStream> > seqInStreams;
CObjectVector< CMyComPtr<ISequentialOutStream> > seqOutStreams;
UInt32 numInStreams = EncodeMode ? 1 : mainCoder.NumStreams;
UInt32 numOutStreams = !EncodeMode ? 1 : mainCoder.NumStreams;
UInt32 startInIndex = EncodeMode ? ci : _bi.Coder_to_Stream[ci];
UInt32 startOutIndex = !EncodeMode ? ci : _bi.Coder_to_Stream[ci];
UInt32 i;
for (i = 0; i < numInStreams; i++)
{
CMyComPtr<ISequentialInStream> seqInStream;
RINOK(GetInStream(inStreams, /* inSizes, */ startInIndex + i, &seqInStream));
seqInStreams.Add(seqInStream);
}
for (i = 0; i < numOutStreams; i++)
{
CMyComPtr<ISequentialOutStream> seqOutStream;
RINOK(GetOutStream(outStreams, /* outSizes, */ startOutIndex + i, &seqOutStream));
seqOutStreams.Add(seqOutStream);
}
CRecordVector< ISequentialInStream * > seqInStreamsSpec;
CRecordVector< ISequentialOutStream * > seqOutStreamsSpec;
for (i = 0; i < numInStreams; i++)
seqInStreamsSpec.Add(seqInStreams[i]);
for (i = 0; i < numOutStreams; i++)
seqOutStreamsSpec.Add(seqOutStreams[i]);
for (i = 0; i < _coders.Size(); i++)
{
if (i == ci)
continue;
CCoder &coder = _coders[i];
if (EncodeMode)
{
CMyComPtr<ICompressInitEncoder> initEncoder;
coder.QueryInterface(IID_ICompressInitEncoder, (void **)&initEncoder);
if (initEncoder)
RINOK(initEncoder->InitEncoder());
}
else
{
CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize);
if (setOutStreamSize)
RINOK(setOutStreamSize->SetOutStreamSize(
EncodeMode ? coder.PackSizePointers[0] : coder.UnpackSizePointer));
}
}
const UInt64 * const *isSizes2 = EncodeMode ? &mainCoder.UnpackSizePointer : &mainCoder.PackSizePointers.Front();
const UInt64 * const *outSizes2 = EncodeMode ? &mainCoder.PackSizePointers.Front() : &mainCoder.UnpackSizePointer;
HRESULT res;
if (mainCoder.Coder)
{
res = mainCoder.Coder->Code(
seqInStreamsSpec[0], seqOutStreamsSpec[0],
isSizes2[0], outSizes2[0],
progress);
}
else
{
res = mainCoder.Coder2->Code(
&seqInStreamsSpec.Front(), isSizes2, numInStreams,
&seqOutStreamsSpec.Front(), outSizes2, numOutStreams,
progress);
}
if (res == k_My_HRESULT_WritingWasCut)
res = S_OK;
if (res == S_OK || res == S_FALSE)
{
res = GetError(res, FinishCoder(ci));
}
for (i = 0; i < _binderStreams.Size(); i++)
{
const CStBinderStream &bs = _binderStreams[i];
if (bs.InStreamSpec)
bs.InStreamSpec->ReleaseStream();
else
bs.OutStreamSpec->ReleaseStream();
}
if (res == k_My_HRESULT_WritingWasCut)
res = S_OK;
return res;
}
HRESULT CMixerST::GetMainUnpackStream(
ISequentialInStream * const *inStreams,
ISequentialInStream **inStreamRes)
{
CMyComPtr<ISequentialInStream> seqInStream;
RINOK(GetInStream2(inStreams, /* inSizes, */
_bi.UnpackCoder, &seqInStream))
FOR_VECTOR (i, _coders)
{
CCoder &coder = _coders[i];
CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize);
if (setOutStreamSize)
{
RINOK(setOutStreamSize->SetOutStreamSize(coder.UnpackSizePointer));
}
}
*inStreamRes = seqInStream.Detach();
return S_OK;
}
UInt64 CMixerST::GetBondStreamSize(unsigned bondIndex) const
{
const CStBinderStream &bs = _binderStreams[bondIndex];
if (bs.InStreamSpec)
return bs.InStreamSpec->GetSize();
return bs.OutStreamSpec->GetSize();
}
#endif
#ifdef USE_MIXER_MT
void CCoderMT::Execute()
{
try
{
Code(NULL);
}
catch(...)
{
Result = E_FAIL;
}
}
void CCoderMT::Code(ICompressProgressInfo *progress)
{
unsigned numInStreams = EncodeMode ? 1 : NumStreams;
unsigned numOutStreams = EncodeMode ? NumStreams : 1;
InStreamPointers.ClearAndReserve(numInStreams);
OutStreamPointers.ClearAndReserve(numOutStreams);
unsigned i;
for (i = 0; i < numInStreams; i++)
InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]);
for (i = 0; i < numOutStreams; i++)
OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]);
// we suppose that UnpackSizePointer and PackSizePointers contain correct pointers.
/*
if (UnpackSizePointer)
UnpackSizePointer = &UnpackSize;
for (i = 0; i < NumStreams; i++)
if (PackSizePointers[i])
PackSizePointers[i] = &PackSizes[i];
*/
CReleaser releaser(*this);
if (Coder)
Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0],
EncodeMode ? UnpackSizePointer : PackSizePointers[0],
EncodeMode ? PackSizePointers[0] : UnpackSizePointer,
progress);
else
Result = Coder2->Code(
&InStreamPointers.Front(), EncodeMode ? &UnpackSizePointer : &PackSizePointers.Front(), numInStreams,
&OutStreamPointers.Front(), EncodeMode ? &PackSizePointers.Front(): &UnpackSizePointer, numOutStreams,
progress);
}
HRESULT CMixerMT::SetBindInfo(const CBindInfo &bindInfo)
{
CMixer::SetBindInfo(bindInfo);
_streamBinders.Clear();
FOR_VECTOR (i, _bi.Bonds)
{
RINOK(_streamBinders.AddNew().CreateEvents());
}
return S_OK;
}
void CMixerMT::AddCoder(const CCreatedCoder &cod)
{
IsFilter_Vector.Add(cod.IsFilter);
IsExternal_Vector.Add(cod.IsExternal);
// const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()];
CCoderMT &c2 = _coders.AddNew();
c2.NumStreams = cod.NumStreams;
c2.Coder = cod.Coder;
c2.Coder2 = cod.Coder2;
c2.EncodeMode = EncodeMode;
}
CCoder &CMixerMT::GetCoder(unsigned index)
{
return _coders[index];
}
void CMixerMT::ReInit()
{
FOR_VECTOR (i, _streamBinders)
_streamBinders[i].ReInit();
}
void CMixerMT::SelectMainCoder(bool useFirst)
{
unsigned ci = _bi.UnpackCoder;
if (!useFirst)
for (;;)
{
if (_coders[ci].NumStreams != 1)
break;
if (!IsFilter_Vector[ci])
break;
UInt32 st = _bi.Coder_to_Stream[ci];
if (_bi.IsStream_in_PackStreams(st))
break;
int bond = _bi.FindBond_for_PackStream(st);
if (bond < 0)
throw 20150213;
ci = _bi.Bonds[bond].UnpackIndex;
}
MainCoderIndex = ci;
}
HRESULT CMixerMT::Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams)
{
unsigned i;
for (i = 0; i < _coders.Size(); i++)
{
CCoderMT &coderInfo = _coders[i];
const CCoderStreamsInfo &csi = _bi.Coders[i];
UInt32 j;
unsigned numInStreams = EncodeMode ? 1 : csi.NumStreams;
unsigned numOutStreams = EncodeMode ? csi.NumStreams : 1;
coderInfo.InStreams.Clear();
for (j = 0; j < numInStreams; j++)
coderInfo.InStreams.AddNew();
coderInfo.OutStreams.Clear();
for (j = 0; j < numOutStreams; j++)
coderInfo.OutStreams.AddNew();
}
for (i = 0; i < _bi.Bonds.Size(); i++)
{
const CBond &bond = _bi.Bonds[i];
UInt32 inCoderIndex, inCoderStreamIndex;
UInt32 outCoderIndex, outCoderStreamIndex;
{
UInt32 coderIndex, coderStreamIndex;
_bi.GetCoder_for_Stream(bond.PackIndex, coderIndex, coderStreamIndex);
inCoderIndex = EncodeMode ? bond.UnpackIndex : coderIndex;
outCoderIndex = EncodeMode ? coderIndex : bond.UnpackIndex;
inCoderStreamIndex = EncodeMode ? 0 : coderStreamIndex;
outCoderStreamIndex = EncodeMode ? coderStreamIndex : 0;
}
_streamBinders[i].CreateStreams(
&_coders[inCoderIndex].InStreams[inCoderStreamIndex],
&_coders[outCoderIndex].OutStreams[outCoderStreamIndex]);
CMyComPtr<ICompressSetBufSize> inSetSize, outSetSize;
_coders[inCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&inSetSize);
_coders[outCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&outSetSize);
if (inSetSize && outSetSize)
{
const UInt32 kBufSize = 1 << 19;
inSetSize->SetInBufSize(inCoderStreamIndex, kBufSize);
outSetSize->SetOutBufSize(outCoderStreamIndex, kBufSize);
}
}
{
CCoderMT &cod = _coders[_bi.UnpackCoder];
if (EncodeMode)
cod.InStreams[0] = inStreams[0];
else
cod.OutStreams[0] = outStreams[0];
}
for (i = 0; i < _bi.PackStreams.Size(); i++)
{
UInt32 coderIndex, coderStreamIndex;
_bi.GetCoder_for_Stream(_bi.PackStreams[i], coderIndex, coderStreamIndex);
CCoderMT &cod = _coders[coderIndex];
if (EncodeMode)
cod.OutStreams[coderStreamIndex] = outStreams[i];
else
cod.InStreams[coderStreamIndex] = inStreams[i];
}
return S_OK;
}
HRESULT CMixerMT::ReturnIfError(HRESULT code)
{
FOR_VECTOR (i, _coders)
if (_coders[i].Result == code)
return code;
return S_OK;
}
HRESULT CMixerMT::Code(
ISequentialInStream * const *inStreams,
ISequentialOutStream * const *outStreams,
ICompressProgressInfo *progress)
{
Init(inStreams, outStreams);
unsigned i;
for (i = 0; i < _coders.Size(); i++)
if (i != MainCoderIndex)
{
RINOK(_coders[i].Create());
}
for (i = 0; i < _coders.Size(); i++)
if (i != MainCoderIndex)
_coders[i].Start();
_coders[MainCoderIndex].Code(progress);
for (i = 0; i < _coders.Size(); i++)
if (i != MainCoderIndex)
_coders[i].WaitExecuteFinish();
RINOK(ReturnIfError(E_ABORT));
RINOK(ReturnIfError(E_OUTOFMEMORY));
for (i = 0; i < _coders.Size(); i++)
{
HRESULT result = _coders[i].Result;
if (result != S_OK
&& result != k_My_HRESULT_WritingWasCut
&& result != S_FALSE
&& result != E_FAIL)
return result;
}
RINOK(ReturnIfError(S_FALSE));
for (i = 0; i < _coders.Size(); i++)
{
HRESULT result = _coders[i].Result;
if (result != S_OK && result != k_My_HRESULT_WritingWasCut)
return result;
}
return S_OK;
}
UInt64 CMixerMT::GetBondStreamSize(unsigned bondIndex) const
{
return _streamBinders[bondIndex].ProcessedSize;
}
#endif
}