#include "avfsincludes.h"
#define AVI_INDEX_OF_INDEXES 0x00
#define AVI_INDEX_OF_CHUNKS 0x01
#define AVI_INDEX_SUB_DEFAULT 0x00
#define AVI_INDEX_SUB_2FIELD 0x01
#define AVIF_HASINDEX 0x00000010
#define AVIF_MUSTUSEINDEX 0x00000020
#define AVIF_ISINTERLEAVED 0x00000100
#ifndef AVIIF_LIST
# define AVIIF_LIST 0x00000001
# define AVIIF_KEYFRAME 0x00000010
#endif
unsigned RiffAlignUp(unsigned size) {
return (size+(2-1))&~(2-1);
}
struct RiffTag
{
uint32_t fcc;
uint32_t cb;
};
static const uint32_t riffFcc = MAKETAGUINT32('R','I','F','F');
static const uint32_t riffLstFcc = MAKETAGUINT32('L','I','S','T');
static const uint32_t riffJunkFcc = MAKETAGUINT32('J','U','N','K');
struct RiffLst {
RiffTag tag;
uint32_t fcc;
};
static const uint32_t avi2MaxSegSize = 0x3FFFFFFE;
static const uint32_t avi2Max4GbSegSize = 0xFFFFFFFE;
static const uint32_t avi2FileFcc = MAKETAGUINT32('A','V','I',' ');
static const uint32_t avi2SegLstFcc = MAKETAGUINT32('A','V','I','X');
static const uint32_t avi2HdrLstFcc = MAKETAGUINT32('h','d','r','l');
static const uint32_t avi2DataLstFcc = MAKETAGUINT32('m','o','v','i');
static const uint32_t avi2MainHdrFcc = MAKETAGUINT32('a','v','i','h');
struct Avi2MainHdr {
RiffTag tag;
uint32_t dwMicroSecPerFrame;
uint32_t dwMaxBytesPerSec;
uint32_t dwPaddingGranularity;
uint32_t dwFlags;
uint32_t dwTotalFrames;
uint32_t dwInitialFrames;
uint32_t dwStreams;
uint32_t dwSuggestedBufferSize;
uint32_t dwWidth;
uint32_t dwHeight;
uint8_t reserved1[16];
};
static const uint32_t avi2StrHdrFcc = MAKETAGUINT32('s','t','r','h');
struct Avi2StrHdr {
RiffTag tag;
uint32_t fccType;
uint32_t fccHandler;
uint32_t dwFlags;
uint16_t wPriority;
uint16_t wLanguage;
uint32_t dwInitialFrames;
uint32_t dwScale;
uint32_t dwRate; uint32_t dwStart;
uint32_t dwLength;
uint32_t dwSuggestedBufferSize;
uint32_t dwQuality;
uint32_t dwSampleSize;
int16_t frameLeft;
int16_t frameTop;
int16_t frameRight;
int16_t frameBottom;
};
static const uint32_t avi2VidFrmtFcc = MAKETAGUINT32('s','t','r','f');
struct Avi2VidFrmt {
RiffTag tag;
uint32_t biSize;
int32_t biWidth;
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPelsPerMeter;
int32_t biYPelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
};
static const uint32_t avi2VidHdrLstFcc = MAKETAGUINT32('s','t','r','l');
static const uint32_t avi2VidStrTypeFcc = MAKETAGUINT32('v','i','d','s');
static const uint32_t avi2AudFrmtFcc = MAKETAGUINT32('s','t','r','f');
struct Avi2AudFrmt {
RiffTag tag;
WaveFormatExtensible wfx;
};
static const uint32_t avi2AudHdrLstFcc = MAKETAGUINT32('s','t','r','l');
static const uint32_t avi2AudStrTypeFcc = MAKETAGUINT32('a','u','d','s');
static const uint32_t avi2IndxFcc = MAKETAGUINT32('i','n','d','x');
struct Avi2IndxHdr {
RiffTag tag;
uint16_t wLongsPerEntry;
uint8_t bIndxSubType;
uint8_t bIndxType;
uint32_t nEntriesInUse;
uint32_t dwChunkId;
uint32_t qwBaseOffsetLow;
uint32_t qwBaseOffsetHigh;
uint8_t reserved1[4];
};
static_assert(sizeof(Avi2IndxHdr) == 32, "");
struct Avi2SuperIndxEntry {
uint32_t qwOffsetLow;
uint32_t qwOffsetHigh;
uint32_t dwSize;
uint32_t dwDuration;
};
static const unsigned avfsAvi2MaxSuperIndxEntryCount = 5000;
struct AvfsAvi2SuperIndx {
Avi2IndxHdr hdr;
Avi2SuperIndxEntry ents[avfsAvi2MaxSuperIndxEntryCount];
};
struct Avi2IndxEntry {
uint32_t dwOffset;
uint32_t dwSize;
};
struct AvfsAvi2Indx {
Avi2IndxHdr hdr;
Avi2IndxEntry ents[1];
};
static const uint32_t avi2ExtHdrFcc = MAKETAGUINT32('d','m','l','h');
struct Avi2ExtHdr {
RiffTag tag;
uint32_t dwGrandFrames;
uint8_t reserved[244];
};
static const uint32_t avi2ExtHdrLstFcc = MAKETAGUINT32('o','d','m','l');
struct Avi2ExtHdrLst {
RiffLst lst;
Avi2ExtHdr hdr;
};
static const uint32_t avi2OldIndxFcc = MAKETAGUINT32('i','d','x','1');
struct Avi2OldIndxEntry {
uint32_t dwChunkId;
uint32_t dwFlags;
uint32_t dwOffset;
uint32_t dwSize;
};
struct AvfsAvi2VidHdrLst {
RiffLst lst;
Avi2StrHdr hdr;
Avi2VidFrmt vidFrmt;
AvfsAvi2SuperIndx indx;
};
struct AvfsAvi2AudHdrLst {
RiffLst lst;
Avi2StrHdr hdr;
Avi2AudFrmt audFrmt;
AvfsAvi2SuperIndx indx;
};
struct AvfsAvi2HdrJunk {
Avi2IndxHdr hdr;
uint8_t junk[10*1024];
};
struct AvfsAvi2HdrLst {
RiffLst lst;
Avi2MainHdr mainHdr;
AvfsAvi2VidHdrLst vidLst;
AvfsAvi2AudHdrLst audLst;
Avi2ExtHdrLst extLst;
AvfsAvi2HdrJunk junk;
};
struct AvfsAvi2Aud {
RiffTag tag;
uint8_t data[1];
};
struct AvfsAvi2Vid {
RiffTag tag;
uint8_t data[1];
};
struct AvfsAvi2DataLst {
RiffLst lst;
uint8_t data[1];
};
struct AvfsAvi2OldIndx {
RiffTag tag;
Avi2OldIndxEntry ents[1];
};
struct AvfsAvi2Seg0 {
RiffLst lst;
AvfsAvi2HdrLst hdrLst;
AvfsAvi2DataLst dataLst;
};
struct AvfsAvi2SegN {
RiffLst lst;
AvfsAvi2DataLst dataLst;
};
static const uint32_t avfsAvi2VidRgbFcc = MAKETAGUINT32('0','0','d','b');
static const uint32_t avfsAvi2VidCompFcc = MAKETAGUINT32('0','0','d','c');
static const uint32_t avfsAvi2AudFcc = MAKETAGUINT32('0','1','w','b');
static const uint32_t avfsAvi2VidIndxFcc = MAKETAGUINT32('i','x','0','0');
static const uint32_t avfsAvi2AudIndxFcc = MAKETAGUINT32('i','x','0','1');
static const unsigned avfsAvi2MaxDataLstSize = avi2MaxSegSize-
offsetof(AvfsAvi2Seg0, dataLst.data)-offsetof(AvfsAvi2OldIndx, ents);
static const unsigned avfsAvi2Max4GbDataLstSize = avi2Max4GbSegSize-
offsetof(AvfsAvi2Seg0, dataLst.data)-offsetof(AvfsAvi2OldIndx, ents);
struct AvfsAvi2File final: AvfsMediaFile_ {
int references = 1;
Synther_* avs = nullptr;
Avisynther_* avssynther = nullptr;
VapourSynther_* vssynther = nullptr;
VideoInfoAdapter vi;
uint32_t frameVidFcc = 0;
unsigned frameAudHdrSize = 0;
unsigned frameVidDataSize = 0;
unsigned frameVidAlignSize = 0;
unsigned vidFrameCount = 0;
unsigned audFrameCount = 0;
unsigned fileFrameCount = 0;
unsigned durFrameCount = 0;
unsigned sampleSize = 0;
unsigned firstAudFramePackCount = 0;
uint64_t fileSampleCount = 0;
unsigned fileSegCount = 0;
uint64_t fileSize = 0;
enum { indxPrePadSize = 0x20000 };
enum { indxPostPadSize = 0x20000 };
struct Seg {
uint64_t startOffset;
unsigned startFrame;
unsigned vidFrameCount;
unsigned audFrameCount;
unsigned frameCount;
unsigned lastAudFramePackCount;
unsigned hdrSize;
unsigned dataSize;
unsigned vidIndxSize;
unsigned audIndxSize;
unsigned oldIndxSize;
unsigned segSize;
unsigned* frameIndx;
AvfsAvi2Indx* vidIndx;
AvfsAvi2Indx* audIndx;
AvfsAvi2OldIndx* oldIndx;
union {
AvfsAvi2Seg0 seg0;
AvfsAvi2SegN segN;
uint8_t buf[1];
} hdr;
};
Seg** segs = nullptr;
uint8_t* sampleScratch = nullptr;
AvfsAvi2File(Avisynther_* avs);
AvfsAvi2File(VapourSynther_* vs);
~AvfsAvi2File(void);
uint64_t LocateFrameSamples(
unsigned frame,
unsigned frameCount,
unsigned* sampleCount);
unsigned FrameSampleCount(unsigned frame) {
unsigned sampleCount;
LocateFrameSamples(frame, 1, &sampleCount);
return sampleCount;
}
bool Init(AvfsLog_* log);
void AddRef(void);
void Release(void);
bool GetFrameData(
AvfsLog_* log,
uint8_t* buffer,
unsigned position,
size_t offset,
size_t size);
bool ReadMedia(
AvfsLog_* log,
uint64_t fileOffset,
void* buffer,
size_t requestedSize);
};
AvfsAvi2File::AvfsAvi2File(Avisynther_* inAvs)
:
vi(inAvs->GetVideoInfo())
{
avs = inAvs;
avssynther = inAvs;
avs->AddRef();
}
AvfsAvi2File::AvfsAvi2File(VapourSynther_* inVs)
:
vi(inVs->GetVideoInfo())
{
avs = inVs;
vssynther = inVs;
avs->AddRef();
}
AvfsAvi2File::~AvfsAvi2File(void)
{
ASSERT(!references);
unsigned segi;
avs->Release();
if (segs) {
for (segi = 0; segi < fileSegCount; segi ++) {
if (segs[segi]) {
free(segs[segi]);
}
}
free(segs);
}
if (sampleScratch) {
free(sampleScratch);
}
}
uint64_t AvfsAvi2File::LocateFrameSamples(
unsigned frame,
unsigned frameCount,
unsigned* outSampleCount)
{
uint64_t startSample = 0;
uint64_t endSample = 0;
unsigned startFrame = frame;
unsigned endFrame = frame+frameCount;
if (startFrame != 0) {
startFrame += firstAudFramePackCount;
}
if (endFrame != 0) {
endFrame += firstAudFramePackCount;
}
if (fileSampleCount) {
startSample = uint64_t(vi.AudioSamplesFromFrames(startFrame));
if (startSample > fileSampleCount) {
startSample = fileSampleCount;
}
endSample = uint64_t(vi.AudioSamplesFromFrames(endFrame));
if (endSample > fileSampleCount) {
endSample = fileSampleCount;
}
}
if(outSampleCount) {
*outSampleCount = unsigned(endSample-startSample);
}
return startSample;
}
bool AvfsAvi2File::Init(
AvfsLog_* log)
{
bool success = true;
unsigned long vidType;
unsigned long vidCompress;
unsigned maxFrameAudDataSize = 0;
uint16_t sampleType = 0;
unsigned clippedSampleCount = 0xFFFFFFFF;
unsigned maxSegFrameCount = 0;
unsigned allocSize;
unsigned segi;
unsigned segSize;
unsigned segStartFrame;
unsigned segVidFrameCount;
unsigned segAudFrameCount;
unsigned segLastAudFramePackCount;
unsigned segFrameCount;
unsigned segDurFrameCount;
unsigned segFrame;
unsigned segHdrSize;
unsigned segDataSize;
unsigned segVidIndxSize;
unsigned segAudIndxSize;
unsigned segOldIndxSize;
uint16_t bitsPerPixel;
uint64_t duration;
Seg* seg;
uint8_t* buf;
Avi2SuperIndxEntry* vidIndxEnts = 0;
Avi2SuperIndxEntry* audIndxEnts = 0;
Avi2OldIndxEntry* oldIndxEnts = 0;
unsigned frameSampleCount;
unsigned frameAudDataSize;
unsigned oldi;
const char* fourcc;
bool noInterleave = false;
vidFrameCount = unsigned(vi.num_frames);
frameVidDataSize = vi.BMPSize();
bitsPerPixel = uint16_t(vi.BitsPerPixel());
vidType = 0;
vidCompress = 0;
bool vidSuccess = true;
if (vi.HasVideo()) {
vidSuccess = vidSuccess && GetFourCC(vi.vf, vi.alt_output, vidType);
vidSuccess = vidSuccess && GetBiCompression(vi.vf, vi.alt_output, vidCompress);
}
if (!vidType || !vidFrameCount || !frameVidDataSize || !vidSuccess) {
vidType = 0;
vidFrameCount = 0;
frameVidDataSize = 0;
} else {
frameVidAlignSize = RiffAlignUp(frameVidDataSize)-frameVidDataSize;
fourcc = avs->GetVarAsString("AVFS_AVI_VidFcc", 0);
if (sslen(fourcc) >= 4) {
vidType = vidCompress = MAKETAGUINT32(
(uint8_t)(fourcc[0]), (uint8_t)(fourcc[1]),
(uint8_t)(fourcc[2]), (uint8_t)(fourcc[3]));
}
}
if (vidType == MAKETAGUINT32('D','I','B',' '))
frameVidFcc = avfsAvi2VidRgbFcc; else
frameVidFcc = avfsAvi2VidCompFcc;
durFrameCount = vidFrameCount;
fileFrameCount = vidFrameCount;
if (vi.HasAudio())
sampleType = vi.AudioIsFloat() ? 2 : 1;
int bytesPerOutputSample = (vi.BitsPerChannelSample() + 7) / 8;
sampleSize = bytesPerOutputSample * vi.AudioChannels();
fileSampleCount = unsigned(vi.num_audio_samples);
if (!sampleType || !sampleSize || !fileSampleCount) {
sampleType = 0;
sampleSize = 0;
fileSampleCount = 0;
}
else {
frameAudHdrSize = sizeof(RiffTag);
maxFrameAudDataSize = RiffAlignUp(unsigned(vi.AudioSamplesFromFrames(1)+1)*sampleSize);
audFrameCount = unsigned(vi.FramesFromAudioSamples(fileSampleCount+vi.AudioSamplesFromFrames(1)-1));
if (!audFrameCount) {
audFrameCount = 1;
}
if (durFrameCount < audFrameCount) {
durFrameCount = audFrameCount;
}
noInterleave = avs->GetVarAsBool("AVFS_AVI_NoInterleave", false);
if (!noInterleave) {
firstAudFramePackCount = unsigned(vi.fps_numerator+vi.fps_denominator-1)/ (unsigned(vi.fps_denominator)*2);
while (audFrameCount && FrameSampleCount(audFrameCount-1) == 0) {
audFrameCount --;
}
}
if (audFrameCount > fileFrameCount) {
fileFrameCount = audFrameCount;
}
}
if (clippedSampleCount > fileSampleCount) {
clippedSampleCount = unsigned(fileSampleCount);
}
if (!vidFrameCount) {
log->Printf(L"AvfsAviMediaInit: Clip has no supported video.\n");
success = false;
}
else {
maxSegFrameCount = ( avfsAvi2Max4GbDataLstSize
- firstAudFramePackCount*maxFrameAudDataSize
- indxPrePadSize
- indxPostPadSize
)
/
( sizeof(RiffTag)
+ maxFrameAudDataSize
+ sizeof(RiffTag)
+ frameVidDataSize
+ frameVidAlignSize
+ sizeof(Avi2IndxEntry)*2
+ sizeof(Avi2OldIndxEntry)*2
);
fileSegCount = (fileFrameCount+maxSegFrameCount-1)/maxSegFrameCount; ASSERT(fileSegCount);
if ( avs->GetVarAsBool("AVFS_AVI_SmallSegments", false))
{
maxSegFrameCount = ( avfsAvi2MaxDataLstSize
- firstAudFramePackCount*maxFrameAudDataSize
- indxPrePadSize
- indxPostPadSize
)
/
( sizeof(RiffTag)
+ maxFrameAudDataSize
+ sizeof(RiffTag)
+ frameVidDataSize
+ frameVidAlignSize
+ sizeof(Avi2IndxEntry)*2
+ sizeof(Avi2OldIndxEntry)*2
);
fileSegCount = (fileFrameCount+maxSegFrameCount-1)/maxSegFrameCount;
}
if (fileSegCount > avfsAvi2MaxSuperIndxEntryCount) {
fileSegCount = avfsAvi2MaxSuperIndxEntryCount;
}
}
if (fileSegCount) {
segs = static_cast<Seg**>(malloc(sizeof(segs[0])*fileSegCount));
if (!segs) {
success = false;
fileSegCount = 0;
}
else {
memset(segs, 0, sizeof(segs[0])*fileSegCount);
}
}
if (sampleSize) {
sampleScratch = static_cast<uint8_t*>(malloc(sampleSize));
if (!sampleScratch) {
success = false;
}
}
segStartFrame = 0;
for (segi = 0; segi < fileSegCount; segi ++) {
segFrameCount = fileFrameCount-segStartFrame;
if (segFrameCount > maxSegFrameCount) {
segFrameCount = maxSegFrameCount;
}
segVidFrameCount = 0;
if (segStartFrame < vidFrameCount) {
segVidFrameCount = vidFrameCount-segStartFrame;
}
if (segVidFrameCount > segFrameCount) {
segVidFrameCount = segFrameCount;
}
segAudFrameCount = 0;
segLastAudFramePackCount = 0;
if (segStartFrame < audFrameCount) {
segAudFrameCount = audFrameCount-segStartFrame;
}
if (segAudFrameCount > segFrameCount) {
segAudFrameCount = segFrameCount;
}
segDurFrameCount = segFrameCount;
if (segi+1 == fileSegCount) {
segDurFrameCount = durFrameCount-segStartFrame;
}
if (noInterleave && segAudFrameCount) {
segLastAudFramePackCount = segAudFrameCount-1;
segAudFrameCount = 1;
}
segHdrSize = offsetof(AvfsAvi2SegN, dataLst.data);
if (segi == 0) {
segHdrSize = offsetof(AvfsAvi2Seg0, dataLst.data);
}
segVidIndxSize = offsetof(AvfsAvi2Indx, ents)+
segVidFrameCount*sizeof(Avi2IndxEntry);
segAudIndxSize = 0;
if (fileSampleCount) {
segAudIndxSize = offsetof(AvfsAvi2Indx, ents)+
segAudFrameCount*sizeof(Avi2IndxEntry);
}
segOldIndxSize = (segi == 0)*(offsetof(AvfsAvi2OldIndx, ents)+
(segVidFrameCount+segAudFrameCount)*sizeof(Avi2OldIndxEntry));
allocSize = offsetof(Seg, hdr)+segHdrSize+
segFrameCount*sizeof(seg->frameIndx[0])+segVidIndxSize+segAudIndxSize+
segOldIndxSize;
seg = segs[segi] = static_cast<Seg*>(malloc(allocSize));
if (!seg) {
success = false;
}
else {
memset(seg, 0, allocSize);
seg->startOffset = fileSize;
seg->startFrame = segStartFrame;
seg->vidFrameCount = segVidFrameCount;
seg->audFrameCount = segAudFrameCount;
seg->frameCount = segFrameCount;
seg->lastAudFramePackCount = segLastAudFramePackCount;
seg->hdrSize = segHdrSize;
seg->vidIndxSize = segVidIndxSize;
seg->audIndxSize = segAudIndxSize;
seg->oldIndxSize = segOldIndxSize;
buf = seg->hdr.buf + segHdrSize;
seg->frameIndx = reinterpret_cast<unsigned*>(buf);
buf += segFrameCount*sizeof(seg->frameIndx[0]);
seg->vidIndx = reinterpret_cast<AvfsAvi2Indx*>(buf);
buf += segVidIndxSize;
seg->audIndx = reinterpret_cast<AvfsAvi2Indx*>(buf);
buf += segAudIndxSize;
seg->oldIndx = reinterpret_cast<AvfsAvi2OldIndx*>(buf);
oldIndxEnts = 0;
if (segi == 0) {
seg->hdr.seg0.lst.tag.fcc = riffFcc; seg->hdr.seg0.lst.fcc = avi2FileFcc;
seg->hdr.seg0.hdrLst.lst.tag.fcc = riffLstFcc; seg->hdr.seg0.hdrLst.lst.tag.cb = sizeof(seg->hdr.seg0.hdrLst)-sizeof(RiffTag);
seg->hdr.seg0.hdrLst.lst.fcc = avi2HdrLstFcc;
seg->hdr.seg0.hdrLst.mainHdr.tag.fcc = avi2MainHdrFcc; seg->hdr.seg0.hdrLst.mainHdr.tag.cb = sizeof(seg->hdr.seg0.hdrLst.mainHdr)-sizeof(RiffTag);
seg->hdr.seg0.hdrLst.mainHdr.dwMicroSecPerFrame = unsigned((uint64_t(1000000)*unsigned(vi.fps_denominator)+unsigned(vi.fps_numerator)/2)/unsigned(vi.fps_numerator));
seg->hdr.seg0.hdrLst.mainHdr.dwFlags = AVIF_HASINDEX | AVIF_ISINTERLEAVED;
seg->hdr.seg0.hdrLst.mainHdr.dwTotalFrames = segDurFrameCount;
seg->hdr.seg0.hdrLst.mainHdr.dwStreams = 1+!!fileSampleCount;
seg->hdr.seg0.hdrLst.mainHdr.dwWidth = vi.width;
seg->hdr.seg0.hdrLst.mainHdr.dwHeight = vi.height;
seg->hdr.seg0.hdrLst.vidLst.lst.tag.fcc = riffLstFcc; seg->hdr.seg0.hdrLst.vidLst.lst.tag.cb = sizeof(seg->hdr.seg0.hdrLst.vidLst)-sizeof(RiffTag);
seg->hdr.seg0.hdrLst.vidLst.lst.fcc = avi2VidHdrLstFcc;
seg->hdr.seg0.hdrLst.vidLst.hdr.tag.fcc = avi2StrHdrFcc; seg->hdr.seg0.hdrLst.vidLst.hdr.tag.cb = sizeof(seg->hdr.seg0.hdrLst.vidLst.hdr)-sizeof(RiffTag);
seg->hdr.seg0.hdrLst.vidLst.hdr.fccType = avi2VidStrTypeFcc; seg->hdr.seg0.hdrLst.vidLst.hdr.fccHandler = vidType;
seg->hdr.seg0.hdrLst.vidLst.hdr.dwScale = vi.fps_denominator;
seg->hdr.seg0.hdrLst.vidLst.hdr.dwRate = vi.fps_numerator;
seg->hdr.seg0.hdrLst.vidLst.hdr.dwLength = vidFrameCount;
seg->hdr.seg0.hdrLst.vidLst.hdr.dwSuggestedBufferSize = frameVidDataSize;
seg->hdr.seg0.hdrLst.vidLst.hdr.dwQuality = 0xFFFFFFFF;
seg->hdr.seg0.hdrLst.vidLst.hdr.frameRight = int16_t(vi.width);
seg->hdr.seg0.hdrLst.vidLst.hdr.frameBottom = int16_t(vi.height);
seg->hdr.seg0.hdrLst.vidLst.vidFrmt.tag.fcc = avi2VidFrmtFcc; seg->hdr.seg0.hdrLst.vidLst.vidFrmt.tag.cb = sizeof(seg->hdr.seg0.hdrLst.vidLst.vidFrmt)-sizeof(RiffTag);
seg->hdr.seg0.hdrLst.vidLst.vidFrmt.biSize = sizeof(seg->hdr.seg0.hdrLst.vidLst.vidFrmt)-sizeof(RiffTag);
seg->hdr.seg0.hdrLst.vidLst.vidFrmt.biWidth = vi.width;
seg->hdr.seg0.hdrLst.vidLst.vidFrmt.biHeight = vi.height;
seg->hdr.seg0.hdrLst.vidLst.vidFrmt.biPlanes = 1;
seg->hdr.seg0.hdrLst.vidLst.vidFrmt.biBitCount = bitsPerPixel;
seg->hdr.seg0.hdrLst.vidLst.vidFrmt.biCompression = vidCompress;
seg->hdr.seg0.hdrLst.vidLst.vidFrmt.biSizeImage = frameVidDataSize;
seg->hdr.seg0.hdrLst.vidLst.indx.hdr.tag.fcc = avi2IndxFcc; seg->hdr.seg0.hdrLst.vidLst.indx.hdr.tag.cb = sizeof(seg->hdr.seg0.hdrLst.vidLst.indx)-sizeof(RiffTag);
seg->hdr.seg0.hdrLst.vidLst.indx.hdr.wLongsPerEntry = sizeof(seg->hdr.seg0.hdrLst.vidLst.indx.ents[0])/4;
seg->hdr.seg0.hdrLst.vidLst.indx.hdr.dwChunkId = frameVidFcc; seg->hdr.seg0.hdrLst.vidLst.indx.hdr.bIndxSubType = AVI_INDEX_SUB_DEFAULT;
seg->hdr.seg0.hdrLst.vidLst.indx.hdr.bIndxType = AVI_INDEX_OF_INDEXES;
seg->hdr.seg0.hdrLst.vidLst.indx.hdr.nEntriesInUse = fileSegCount;
seg->hdr.seg0.hdrLst.audLst.lst.tag.fcc = fileSampleCount?riffLstFcc:riffJunkFcc; seg->hdr.seg0.hdrLst.audLst.lst.tag.cb = sizeof(seg->hdr.seg0.hdrLst.audLst)-sizeof(RiffTag);
seg->hdr.seg0.hdrLst.audLst.lst.fcc = avi2AudHdrLstFcc;
seg->hdr.seg0.hdrLst.audLst.hdr.tag.fcc = avi2StrHdrFcc; seg->hdr.seg0.hdrLst.audLst.hdr.tag.cb = sizeof(seg->hdr.seg0.hdrLst.audLst.hdr)-sizeof(RiffTag);
seg->hdr.seg0.hdrLst.audLst.hdr.fccType = avi2AudStrTypeFcc; seg->hdr.seg0.hdrLst.audLst.hdr.dwInitialFrames = 1; seg->hdr.seg0.hdrLst.audLst.hdr.dwScale = sampleSize;
seg->hdr.seg0.hdrLst.audLst.hdr.dwRate = vi.SamplesPerSecond()*sampleSize;
seg->hdr.seg0.hdrLst.audLst.hdr.dwLength = clippedSampleCount;
seg->hdr.seg0.hdrLst.audLst.hdr.dwSuggestedBufferSize = unsigned(LocateFrameSamples(1, 1, 0)+1)*sampleSize;
seg->hdr.seg0.hdrLst.audLst.hdr.dwQuality = 0xFFFFFFFF;
seg->hdr.seg0.hdrLst.audLst.hdr.dwSampleSize = sampleSize;
seg->hdr.seg0.hdrLst.audLst.audFrmt.tag.fcc = avi2AudFrmtFcc; seg->hdr.seg0.hdrLst.audLst.audFrmt.tag.cb = sizeof(seg->hdr.seg0.hdrLst.audLst.audFrmt)-sizeof(RiffTag);
CreateWaveFormatExtensible(seg->hdr.seg0.hdrLst.audLst.audFrmt.wfx, sampleType == 2, vi.BitsPerChannelSample(), vi.SamplesPerSecond(), vi.ChannelLayout());
seg->hdr.seg0.hdrLst.audLst.indx.hdr.tag.fcc = avi2IndxFcc; seg->hdr.seg0.hdrLst.audLst.indx.hdr.tag.cb = sizeof(seg->hdr.seg0.hdrLst.audLst.indx)-sizeof(RiffTag);
seg->hdr.seg0.hdrLst.audLst.indx.hdr.wLongsPerEntry = sizeof(seg->hdr.seg0.hdrLst.audLst.indx.ents[0])/4;
seg->hdr.seg0.hdrLst.audLst.indx.hdr.dwChunkId = avfsAvi2AudFcc; seg->hdr.seg0.hdrLst.audLst.indx.hdr.bIndxSubType = AVI_INDEX_SUB_DEFAULT;
seg->hdr.seg0.hdrLst.audLst.indx.hdr.bIndxType = AVI_INDEX_OF_INDEXES;
seg->hdr.seg0.hdrLst.audLst.indx.hdr.nEntriesInUse = fileSegCount;
seg->hdr.seg0.hdrLst.extLst.lst.tag.fcc = riffLstFcc; seg->hdr.seg0.hdrLst.extLst.lst.tag.cb = sizeof(seg->hdr.seg0.hdrLst.extLst)-sizeof(RiffTag);
seg->hdr.seg0.hdrLst.extLst.lst.fcc = avi2ExtHdrLstFcc;
seg->hdr.seg0.hdrLst.extLst.hdr.tag.fcc = avi2ExtHdrFcc; seg->hdr.seg0.hdrLst.extLst.hdr.tag.cb = sizeof(seg->hdr.seg0.hdrLst.extLst.hdr)-sizeof(RiffTag);
seg->hdr.seg0.hdrLst.extLst.hdr.dwGrandFrames = durFrameCount;
seg->hdr.seg0.hdrLst.junk.hdr.tag.fcc = riffJunkFcc; seg->hdr.seg0.hdrLst.junk.hdr.tag.cb = sizeof(seg->hdr.seg0.hdrLst.junk)-sizeof(RiffTag);
seg->hdr.seg0.dataLst.lst.tag.fcc = riffLstFcc; seg->hdr.seg0.dataLst.lst.fcc = avi2DataLstFcc;
vidIndxEnts = seg->hdr.seg0.hdrLst.vidLst.indx.ents;
audIndxEnts = seg->hdr.seg0.hdrLst.audLst.indx.ents;
oldIndxEnts = seg->oldIndx->ents;
}
else {
seg->hdr.segN.lst.tag.fcc = riffFcc; seg->hdr.segN.lst.fcc = avi2SegLstFcc;
seg->hdr.segN.dataLst.lst.tag.fcc = riffLstFcc; seg->hdr.segN.dataLst.lst.fcc = avi2DataLstFcc; }
segSize = segHdrSize;
oldi = 0;
segDataSize = 0;
for (segFrame = 0; segFrame < segFrameCount; segFrame ++) {
seg->frameIndx[segFrame] = segDataSize;
if (segFrame < segAudFrameCount) {
LocateFrameSamples(segStartFrame+segFrame,
(segFrame+1 == segAudFrameCount) ? segLastAudFramePackCount+1 : 1,
&frameSampleCount);
ASSERT(frameSampleCount);
frameAudDataSize = frameSampleCount*sampleSize;
seg->audIndx->ents[segFrame].dwOffset = segSize+segDataSize + sizeof(RiffTag);
seg->audIndx->ents[segFrame].dwSize = frameAudDataSize;
if (oldIndxEnts) {
oldIndxEnts[oldi].dwChunkId = avfsAvi2AudFcc; oldIndxEnts[oldi].dwFlags = AVIIF_KEYFRAME;
oldIndxEnts[oldi].dwOffset = segSize+segDataSize;
oldIndxEnts[oldi].dwSize = frameAudDataSize;
oldi ++;
}
segDataSize += sizeof(RiffTag)+RiffAlignUp(frameAudDataSize);
}
if (segFrame < segVidFrameCount) {
seg->vidIndx->ents[segFrame].dwOffset = segSize+segDataSize+sizeof(RiffTag);
seg->vidIndx->ents[segFrame].dwSize = frameVidDataSize;
if (oldIndxEnts) {
oldIndxEnts[oldi].dwChunkId = frameVidFcc;
oldIndxEnts[oldi].dwFlags = AVIIF_KEYFRAME;
oldIndxEnts[oldi].dwOffset = segSize+segDataSize;
oldIndxEnts[oldi].dwSize = frameVidDataSize;
oldi ++;
}
segDataSize += sizeof(RiffTag)+frameVidDataSize+frameVidAlignSize;
}
}
seg->dataSize = segDataSize;
segSize += segDataSize;
segSize += indxPrePadSize;
seg->vidIndx->hdr.tag.fcc = avfsAvi2VidIndxFcc; seg->vidIndx->hdr.tag.cb = segVidIndxSize-sizeof(RiffTag);
seg->vidIndx->hdr.wLongsPerEntry = sizeof(seg->vidIndx->ents[0])/4;
seg->vidIndx->hdr.bIndxType = AVI_INDEX_OF_CHUNKS;
seg->vidIndx->hdr.nEntriesInUse = segVidFrameCount;
seg->vidIndx->hdr.dwChunkId = frameVidFcc;
seg->vidIndx->hdr.qwBaseOffsetLow = uint32_t(fileSize);
seg->vidIndx->hdr.qwBaseOffsetHigh = uint32_t(fileSize>>32);
vidIndxEnts[segi].qwOffsetLow = uint32_t(fileSize+segSize);
vidIndxEnts[segi].qwOffsetHigh = uint32_t((fileSize+segSize)>>32);
vidIndxEnts[segi].dwSize = offsetof(AvfsAvi2Indx, ents)+sizeof(seg->vidIndx->ents[0])*segFrameCount;
vidIndxEnts[segi].dwDuration = segVidFrameCount;
segSize += segVidIndxSize;
if (fileSampleCount) {
LocateFrameSamples(segStartFrame, segAudFrameCount+segLastAudFramePackCount, &frameSampleCount);
seg->audIndx->hdr.tag.fcc = avfsAvi2AudIndxFcc; seg->audIndx->hdr.tag.cb = segAudIndxSize-sizeof(RiffTag);
seg->audIndx->hdr.wLongsPerEntry = sizeof(seg->audIndx->ents[0])/4;
seg->audIndx->hdr.bIndxType = AVI_INDEX_OF_CHUNKS;
seg->audIndx->hdr.nEntriesInUse = segAudFrameCount;
seg->audIndx->hdr.dwChunkId = avfsAvi2AudFcc; seg->audIndx->hdr.qwBaseOffsetLow = uint32_t(fileSize);
seg->audIndx->hdr.qwBaseOffsetHigh = uint32_t(fileSize>>32);
audIndxEnts[segi].qwOffsetLow = uint32_t(fileSize+segSize);
audIndxEnts[segi].qwOffsetHigh = uint32_t((fileSize+segSize)>>32);
audIndxEnts[segi].dwSize = offsetof(AvfsAvi2Indx, ents)+sizeof(seg->audIndx->ents[0])*segFrameCount;
audIndxEnts[segi].dwDuration = frameSampleCount;
segSize += segAudIndxSize;
}
if (segi == 0) {
seg->hdr.seg0.dataLst.lst.tag.cb = segSize-offsetof(AvfsAvi2Seg0, dataLst)-sizeof(RiffTag);
}
else {
seg->hdr.segN.dataLst.lst.tag.cb = segSize-offsetof(AvfsAvi2SegN, dataLst)-sizeof(RiffTag);
}
if (segOldIndxSize) {
seg->oldIndx->tag.fcc = avi2OldIndxFcc;
seg->oldIndx->tag.cb = segOldIndxSize-sizeof(RiffTag);
segSize += segOldIndxSize;
}
segSize += indxPostPadSize;
if (segi == 0) {
seg->hdr.seg0.lst.tag.cb = segSize-sizeof(RiffTag);
}
else {
seg->hdr.segN.lst.tag.cb = segSize-sizeof(RiffTag);
}
seg->segSize = segSize;
ASSERT(RiffAlignUp(segSize) == segSize);
ASSERT(segSize <= avi2Max4GbSegSize);
fileSize += segSize;
}
segStartFrame += segFrameCount;
}
if (segs && segs[0]) {
duration = (uint64_t(durFrameCount)*unsigned(vi.fps_denominator)+
unsigned(vi.fps_numerator)/2)/unsigned(vi.fps_numerator);
duration += !duration;
segs[0]->hdr.seg0.hdrLst.mainHdr.dwMaxBytesPerSec = unsigned(fileSize/duration);
}
ASSERT(!success || segStartFrame == fileFrameCount);
return success;
}
void AvfsAvi2File::AddRef(void)
{
ASSERT(references);
references ++;
}
void AvfsAvi2File::Release(void)
{
ASSERT(references);
if (!--references) {
delete this;
}
}
static void copyPlaneAvs(
const VSVideoFormat &fi,
uint8_t* &buffer,
size_t &offset,
size_t &rqsize,
avs::PVideoFrame &frame,
int plane,
unsigned alignMask,
int alt_output)
{
if (rqsize) {
if (NeedsUVSwap(fi, alt_output)) {
if (plane == avs::PLANAR_V)
plane = avs::PLANAR_U;
else if (plane == avs::PLANAR_U)
plane = avs::PLANAR_V;
}
const unsigned rowsize = (frame->GetRowSize(plane) + alignMask) & ~alignMask;
const unsigned plsize = frame->GetHeight(plane) * rowsize;
const unsigned pitch = frame->GetPitch(plane);
if (offset < plsize) {
size_t size = std::min(plsize - offset, rqsize);
const uint8_t* data = frame->GetReadPtr(plane);
data += (offset / rowsize) * pitch;
size_t initoff = offset % rowsize;
offset += size;
rqsize -= size;
while (size > 0) {
size_t xfer = std::min(rowsize-initoff, size);
memcpy(buffer, data+initoff, xfer);
buffer += xfer;
size -= xfer;
data += pitch;
initoff = 0;
}
}
offset -= plsize;
}
}
static void copyPlaneVS(
const VSVideoFormat &fi,
uint8_t* &buffer,
size_t &offset,
size_t &rqsize,
const VSFrame *frame,
int plane,
unsigned alignMask,
int alt_output,
const VSAPI *vsapi) {
if (rqsize) {
if (NeedsUVSwap(fi, alt_output)) {
if (plane == 2)
plane = 1;
else if (plane == 1)
plane = 2;
}
const unsigned rowsize = (vsapi->getFrameWidth(frame, plane) * fi.bytesPerSample + alignMask) & ~alignMask;
const unsigned plsize = vsapi->getFrameHeight(frame, plane) * rowsize;
const ptrdiff_t pitch = vsapi->getStride(frame, plane);
if (offset < plsize) {
size_t size = std::min(plsize - offset, rqsize);
const uint8_t* data = vsapi->getReadPtr(frame, plane);
data += (offset / rowsize) * pitch;
size_t initoff = offset % rowsize;
offset += size;
rqsize -= size;
while (size > 0) {
size_t xfer = std::min(rowsize - initoff, size);
memcpy(buffer, data + initoff, xfer);
buffer += xfer;
size -= xfer;
data += pitch;
initoff = 0;
}
}
offset -= plsize;
}
}
bool AvfsAvi2File::GetFrameData(
AvfsLog_* log,
uint8_t* buffer,
unsigned n,
size_t offset,
size_t size)
{
ASSERT(offset < frameVidDataSize && offset+size <= frameVidDataSize);
bool success = true;
if (vssynther) {
const VSAPI *vsapi = vssynther->GetVSApi();
const VSFrame *frame = vssynther->GetFrame(log, n, &success);
if (success) {
VideoInfoAdapter via = vssynther->GetVideoInfo();
if (NeedsPacking(via.vf, via.alt_output)) {
memcpy(buffer, vssynther->GetPackedFrame() + offset, size);
} else {
copyPlaneVS(via.vf, buffer, offset, size, frame, 0, (via.vf.numPlanes == 1) ? 3 : 0, via.alt_output, vsapi);
copyPlaneVS(via.vf, buffer, offset, size, frame, 2, 0, via.alt_output, vsapi);
copyPlaneVS(via.vf, buffer, offset, size, frame, 1, 0, via.alt_output, vsapi);
ASSERT(size == 0);
}
}
vsapi->freeFrame(frame);
} else {
avs::PVideoFrame frame = avssynther->GetFrame(log, n, &success);
if (success) {
VideoInfoAdapter via = avssynther->GetVideoInfo();
if (NeedsPacking(via.vf, via.alt_output)) {
memcpy(buffer, avssynther->GetPackedFrame() + offset, size);
} else {
copyPlaneAvs(via.vf, buffer, offset, size, frame, avs::PLANAR_Y, (via.vf.numPlanes == 1) ? 3 : 0, via.alt_output);
copyPlaneAvs(via.vf, buffer, offset, size, frame, avs::PLANAR_V, 0, via.alt_output);
copyPlaneAvs(via.vf, buffer, offset, size, frame, avs::PLANAR_U, 0, via.alt_output);
ASSERT(size == 0);
}
}
}
return success;
}
bool AvfsAvi2File::ReadMedia(
AvfsLog_* log,
uint64_t inFileOffset,
void* inBuffer,
size_t inRequestedSize)
{
ASSERT(inRequestedSize);
ASSERT(inFileOffset < fileSize);
ASSERT(inFileOffset+inRequestedSize <= fileSize);
bool success = true;
uint64_t fileOffset = inFileOffset;
size_t remainingSize = inRequestedSize;
uint8_t* buffer = static_cast<uint8_t*>(inBuffer);
unsigned segi = 0;
size_t offset = 0;
unsigned b;
RiffTag riffTag;
Seg* seg;
ASSERT(fileSegCount);
b = 1;
while (b < fileSegCount) {
b <<= 1;
}
segi = 0;
while ((b >>= 1) != 0) {
segi |= b;
if (segi >= fileSegCount || segs[segi]->startOffset > fileOffset) {
segi &= ~b;
}
}
offset = unsigned(fileOffset-segs[segi]->startOffset);
while (success && remainingSize) {
seg = segs[segi];
if (offset >= seg->hdrSize) {
offset -= seg->hdrSize;
}
else {
if (remainingSize) {
size_t partSize = seg->hdrSize-offset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
if (partSize) {
memcpy(buffer, reinterpret_cast<uint8_t*>(&(seg->hdr))+offset,
partSize);
}
buffer += partSize;
remainingSize -= partSize;
}
offset = 0;
}
unsigned segFrame = 0;
if (offset >= seg->dataSize) {
offset -= seg->dataSize;
segFrame = UINT_MAX;
}
else
{
b = 1;
while (b < seg->frameCount) {
b <<= 1;
}
while ((b >>= 1) != 0) {
segFrame |= b;
if (segFrame >= seg->frameCount || (seg->frameIndx[segFrame] > offset)) {
segFrame &= ~b;
}
}
offset -= seg->frameIndx[segFrame];
}
while (remainingSize && segFrame < seg->frameCount) {
if(segFrame < seg->audFrameCount) {
unsigned sampleCount;
uint64_t startSample = LocateFrameSamples(seg->startFrame+segFrame,
(segFrame+1 == seg->audFrameCount) ? seg->lastAudFramePackCount+1 : 1,
&sampleCount);
ASSERT(sampleCount);
unsigned audDataSize = sampleCount*sampleSize;
unsigned audAlignSize = RiffAlignUp(audDataSize)-audDataSize;
if (offset >= sizeof(riffTag)) {
offset -= sizeof(riffTag);
}
else {
if (remainingSize) {
riffTag.fcc = avfsAvi2AudFcc; riffTag.cb = audDataSize;
size_t partSize = sizeof(riffTag)-offset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
memcpy(buffer, reinterpret_cast<uint8_t*>(&riffTag)+offset,
partSize);
buffer += partSize;
remainingSize -= partSize;
}
offset = 0;
}
if (offset >= audDataSize) {
offset -= audDataSize;
}
else {
unsigned extraOffset = offset%sampleSize;
if (remainingSize && extraOffset) {
size_t partSize = sampleSize-extraOffset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
success = success && avs->GetAudio(log, sampleScratch,
offset/sampleSize, 1);
memcpy(buffer, sampleScratch+extraOffset, partSize);
buffer += partSize;
remainingSize -= partSize;
offset += partSize;
}
if (offset < audDataSize && remainingSize >= sampleSize) {
ASSERT(offset%sampleSize == 0);
size_t partSize = audDataSize-offset;
if (partSize > remainingSize) {
partSize = remainingSize-remainingSize%sampleSize;
}
success = success && avs->GetAudio(log, buffer, startSample+
offset/sampleSize, int(partSize/sampleSize));
buffer += partSize;
remainingSize -= partSize;
offset += partSize;
}
if (offset < audDataSize && remainingSize) {
ASSERT(remainingSize < sampleSize);
success = success && avs->GetAudio(log, sampleScratch,
startSample+offset/sampleSize, 1);
memcpy(buffer, sampleScratch, remainingSize);
buffer += remainingSize;
remainingSize = 0;
}
offset = 0;
}
if (offset >= audAlignSize) {
offset -= audAlignSize;
}
else {
if (remainingSize) {
size_t partSize = audAlignSize-offset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
memset(buffer, 0, remainingSize);
buffer += remainingSize;
remainingSize = 0;
}
offset = 0;
}
}
if (segFrame < seg->vidFrameCount) {
if (offset >= sizeof(riffTag)) {
offset -= sizeof(riffTag);
}
else {
if (remainingSize) {
riffTag.fcc = frameVidFcc;
riffTag.cb = frameVidDataSize;
size_t partSize = sizeof(riffTag)-offset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
memcpy(buffer, reinterpret_cast<uint8_t*>(&riffTag)+offset,
partSize);
buffer += partSize;
remainingSize -= partSize;
}
offset = 0;
}
if (offset >= frameVidDataSize) {
offset -= frameVidDataSize;
}
else {
if (remainingSize) {
size_t partSize = frameVidDataSize-offset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
success = success && GetFrameData(log, buffer,
seg->startFrame+segFrame, offset, partSize);
buffer += partSize;
remainingSize -= partSize;
}
offset = 0;
}
if (offset >= frameVidAlignSize) {
offset -= frameVidAlignSize;
}
else {
if (remainingSize) {
size_t partSize = frameVidAlignSize-offset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
memset(buffer, 0, remainingSize);
buffer += remainingSize;
remainingSize = 0;
}
offset = 0;
}
}
segFrame ++;
#ifndef NDEBUG
unsigned temp = seg->dataSize;
if(segFrame < seg->frameCount) {
temp = seg->frameIndx[segFrame];
}
temp -= seg->frameIndx[segFrame-1];
#endif
}
if (offset >= indxPrePadSize) {
offset -= indxPrePadSize;
}
else {
ASSERT(indxPrePadSize >= sizeof(riffTag));
if (offset >= sizeof(riffTag)) {
offset -= sizeof(riffTag);
}
else {
if (remainingSize) {
riffTag.fcc = riffJunkFcc;
riffTag.cb = indxPrePadSize-sizeof(riffTag);
size_t partSize = sizeof(riffTag)-offset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
memcpy(buffer, reinterpret_cast<uint8_t*>(&riffTag)+offset,
partSize);
buffer += partSize;
remainingSize -= partSize;
}
offset = 0;
}
if (remainingSize) {
size_t partSize = indxPrePadSize-sizeof(riffTag)-offset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
memset(buffer, 0, partSize);
buffer += partSize;
remainingSize -= partSize;
}
offset = 0;
}
if (offset >= seg->vidIndxSize) {
offset -= seg->vidIndxSize;
}
else {
if (remainingSize) {
size_t partSize = seg->vidIndxSize-offset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
memcpy(buffer, reinterpret_cast<uint8_t*>(seg->vidIndx)+offset,
partSize);
buffer += partSize;
remainingSize -= partSize;
}
offset = 0;
}
if (offset >= seg->audIndxSize) {
offset -= seg->audIndxSize;
}
else {
if (remainingSize) {
size_t partSize = seg->audIndxSize-offset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
memcpy(buffer, reinterpret_cast<uint8_t*>(seg->audIndx)+offset,
partSize);
buffer += partSize;
remainingSize -= partSize;
}
offset = 0;
}
if (offset >= seg->oldIndxSize) {
offset -= seg->oldIndxSize;
}
else {
if (remainingSize) {
size_t partSize = seg->oldIndxSize-offset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
memcpy(buffer, reinterpret_cast<uint8_t*>(seg->oldIndx)+offset,
partSize);
buffer += partSize;
remainingSize -= partSize;
}
offset = 0;
}
if (offset >= indxPostPadSize) {
offset -= indxPostPadSize;
}
else {
ASSERT(sizeof(riffTag) <= indxPostPadSize);
if (offset >= sizeof(riffTag)) {
offset -= sizeof(riffTag);
}
else {
if (remainingSize) {
riffTag.fcc = riffJunkFcc;
riffTag.cb = indxPostPadSize-sizeof(riffTag);
size_t partSize = sizeof(riffTag)-offset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
memcpy(buffer, reinterpret_cast<uint8_t*>(&riffTag)+offset,
partSize);
buffer += partSize;
remainingSize -= partSize;
}
offset = 0;
}
if (remainingSize) {
size_t partSize = indxPostPadSize-sizeof(riffTag)-offset;
if (partSize > remainingSize) {
partSize = remainingSize;
}
memset(buffer, 0, partSize);
buffer += partSize;
remainingSize -= partSize;
}
offset = 0;
}
segi++;
offset = 0;
}
return success;
}
void AvfsAviMediaInit(
AvfsLog_* log,
Avisynther_* avs,
AvfsVolume_* volume)
{
ASSERT(log && avs && volume);
static const size_t maxNameChars = 300;
wchar_t name[maxNameChars];
AvfsAvi2File* avi = new(std::nothrow) AvfsAvi2File(avs);
if (avi && !avi->Init(log)) {
avi->Release();
avi = 0;
}
if (avi) {
ssformat(name, maxNameChars, L"%s.avi", volume->GetMediaName());
volume->CreateMediaFile(avi, name, avi->fileSize);
avi->Release();
}
}
void VsfsAviMediaInit(
AvfsLog_* log,
VapourSynther_* avs,
AvfsVolume_* volume) {
ASSERT(log && avs && volume);
static const size_t maxNameChars = 300;
wchar_t name[maxNameChars];
AvfsAvi2File* avi = new(std::nothrow) AvfsAvi2File(avs);
if (avi && !avi->Init(log)) {
avi->Release();
avi = 0;
}
if (avi) {
ssformat(name, maxNameChars, L"%s.avi", volume->GetMediaName());
volume->CreateMediaFile(avi, name, avi->fileSize);
avi->Release();
}
}