📄 videosource.cpp
字号:
fUseGDI = true;
} else if (!is_dib) {
FOURCC fccOriginalCodec = bmih->biCompression;
// 如果是老式的MPEG-4解码器,尝试所有的已知的老式解码器
// 它们都是同种的解码器,因此互相兼容
switch(bmih->biCompression) {
case '34PM': // Microsoft MPEG-4 V3
case '3VID': // "DivX Low-Motion" (4.10.0.3917)
case '4VID': // "DivX Fast-Motion" (4.10.0.3920)
case '14PA': // "AngelPotion Definitive" (4.0.00.3688)
if (AttemptCodecNegotiation(bmih, is_mjpeg)) return;
bmih->biCompression = '34PM';
if (AttemptCodecNegotiation(bmih, is_mjpeg)) return;
bmih->biCompression = '3VID';
if (AttemptCodecNegotiation(bmih, is_mjpeg)) return;
bmih->biCompression = '4VID';
if (AttemptCodecNegotiation(bmih, is_mjpeg)) return;
bmih->biCompression = '14PA';
default:
if (AttemptCodecNegotiation(bmih, is_mjpeg)) return;
break;
}
const char *s = LookupVideoCodec(fccOriginalCodec);
throw MyError("Couldn't locate decompressor for format '%c%c%c%c' (%s)\n"
"\n"
"VirtualDub requires a Video for Windows (VFW) compatible codec to decompress "
"video. DirectShow codecs, such as those used by Windows Media Player, are not "
"suitable."
,(fccOriginalCodec ) & 0xff
,(fccOriginalCodec>> 8) & 0xff
,(fccOriginalCodec>>16) & 0xff
,(fccOriginalCodec>>24) & 0xff
,s ? s : "unknown");
}
}
bool VideoSourceAVI::AttemptCodecNegotiation(BITMAPINFOHEADER *bmih, bool is_mjpeg) {
// VideoMatrix sets streamInfo.fccHandler to NULL. Danger, Will Robinson.
if (!use_internal) {
// Try the handler specified in the file first. In some cases, it'll
// be wrong or missing.
if (streamInfo.fccHandler)
hicDecomp = ICOpen(ICTYPE_VIDEO, streamInfo.fccHandler, ICMODE_DECOMPRESS);
if (!hicDecomp || ICERR_OK!=ICDecompressQuery(hicDecomp, bmih, NULL)) {
if (hicDecomp)
ICClose(hicDecomp);
// Pick a handler based on the biCompression field instead.
hicDecomp = ICOpen(ICTYPE_VIDEO, bmih->biCompression, ICMODE_DECOMPRESS);
if (!hicDecomp || ICERR_OK!=ICDecompressQuery(hicDecomp, bmih, NULL)) {
if (hicDecomp)
ICClose(hicDecomp);
// AngelPotion f*cks us over here and overwrites our format if we keep this in.
// So let's write protect the format. You'll see a nice C0000005 error when
// the AP DLL tries to modify it.
// hicDecomp = ICLocate(ICTYPE_VIDEO, NULL, getImageFormat(), NULL, ICMODE_DECOMPRESS);
int siz = getFormatLen();
BITMAPINFOHEADER *pbih_protected = (BITMAPINFOHEADER *)VirtualAlloc(NULL, siz, MEM_COMMIT, PAGE_READWRITE);
if (pbih_protected) {
DWORD dwOldProtect;
memcpy(pbih_protected, bmih, siz);
VirtualProtect(pbih_protected, siz, PAGE_READONLY, &dwOldProtect);
hicDecomp = ICLocate(ICTYPE_VIDEO, NULL, pbih_protected, NULL, ICMODE_DECOMPRESS);
VirtualFree(pbih_protected, 0, MEM_RELEASE);
}
}
}
}
if (!hicDecomp) {
// Is it MJPEG or I420? Maybe we can do it ourselves.
if (is_mjpeg) {
// if (!(mdec = CreateMJPEGDecoder(getImageFormat()->biWidth, getImageFormat()->biHeight)))
// throw MyMemoryError();
return true;
} else {
return false;
}
} else {
// check for bad MPEG-4 V2/V3 codec
if (isEqualFOURCC(bmih->biCompression, '24PM'))
return CheckMPEG4Codec(hicDecomp, false);
else if (isEqualFOURCC(bmih->biCompression, '34PM'))
return CheckMPEG4Codec(hicDecomp, true);
else
return true;
}
}
///////////////////////////////////////////////////////////////////////////
void VideoSourceAVI::Reinit() {
long nOldFrames, nNewFrames;
nOldFrames = lSampleLast - lSampleFirst;
nNewFrames = pAVIStream->End() - pAVIStream->Start();
if (mjpeg_splits) {
nOldFrames >>= 1;
}
if (nOldFrames != nNewFrames && (mjpeg_mode==IFMODE_SPLIT1 || mjpeg_mode==IFMODE_SPLIT2)) {
// We have to resize the mjpeg_splits array.
long *pNewSplits = new long[lSampleLast - lSampleFirst];
if (!pNewSplits)
throw MyMemoryError();
int i;
memcpy(pNewSplits, mjpeg_splits, sizeof(long)*nOldFrames);
for(i=nOldFrames; i<nNewFrames; i++)
pNewSplits[i] = -1;
delete[] mjpeg_splits;
mjpeg_splits = pNewSplits;
}
if (pAVIStream->Info(&streamInfo, sizeof streamInfo))
throw MyError("Error obtaining video stream info.");
lSampleFirst = pAVIStream->Start();
if (mjpeg_splits) {
streamInfo.dwRate *= 2;
streamInfo.dwLength *= 2;
lSampleLast = pAVIStream->End() * 2 - lSampleFirst;
} else
lSampleLast = pAVIStream->End();
streamInfo.dwLength = lSampleLast - lSampleFirst;
}
void VideoSourceAVI::redoKeyFlags() {
long lSample;
long lMaxFrame=0;
long lActualBytes, lActualSamples;
int err;
void *lpInputBuffer = NULL;
void *lpKeyBuffer = NULL;
BOOL fStreamBegun = FALSE;
int iBytes;
long *pFrameSums;
if (!hicDecomp)
return;
iBytes = (lSampleLast+7-lSampleFirst)>>3;
if (!(key_flags = new char[iBytes]))
throw MyMemoryError();
memset(key_flags, 0, iBytes);
// Find maximum frame
lSample = lSampleFirst;
while(lSample < lSampleLast) {
err = _read(lSample, 1, NULL, 0, &lActualBytes, &lActualSamples);
if (err == AVIERR_OK)
// throw MyAVIError("VideoSource", err);
if (lActualBytes > lMaxFrame) lMaxFrame = lActualBytes;
++lSample;
}
if (!setDecompressedFormat(24))
if (!setDecompressedFormat(32))
if (!setDecompressedFormat(16))
if (!setDecompressedFormat(8))
throw MyError("Video decompressor is incapable of decompressing to an RGB format.");
if (!(lpInputBuffer = new char[((lMaxFrame+7)&-8) + lMaxFrame]))
throw MyMemoryError();
if (!(pFrameSums = new long[lSampleLast - lSampleFirst])) {
delete[] lpInputBuffer;
throw MyMemoryError();
}
try {
// ProgressDialog pd(NULL, "AVI Import Filter", "Rekeying video stream", (lSampleLast - lSampleFirst)*2, true);
// pd.setValueFormat("Frame %ld of %ld");
MessageBox( NULL, "AVI Import Filter", "Rekeying video stream", MB_OK);
streamBegin(true);
fStreamBegun = TRUE;
lSample = lSampleFirst;
while(lSample < lSampleLast) {
long lBlackTotal=0, lWhiteTotal=0;
long x, y;
const long lWidth = (bmihDecompressedFormat->biWidth * bmihDecompressedFormat->biBitCount + 7)/8;
const long lModulo = (4-lWidth)&3;
const long lHeight = bmihDecompressedFormat->biHeight;
unsigned char *ptr;
_RPT1(0,"Rekeying frame %ld\n", lSample);
err = _read(lSample, 1, lpInputBuffer, lMaxFrame, &lActualBytes, &lActualSamples);
if (err != AVIERR_OK)
// throw MyAVIError("VideoSourceAVI", err);
goto rekey_error;
#if 0
// decompress frame with an all black background
memset(lpvBuffer, 0, bmihDecompressedFormat->biSizeImage);
streamGetFrame(lpInputBuffer, lActualBytes, FALSE, FALSE, lSample);
ptr = (unsigned char *)lpvBuffer;
y = lHeight;
do {
x = lWidth;
do {
lBlackTotal += (long)*ptr++;
} while(--x);
ptr += lModulo;
} while(--y);
// decompress frame with an all white background
memset(lpvBuffer, 0xff, bmihDecompressedFormat->biSizeImage);
streamGetFrame(lpInputBuffer, lActualBytes, FALSE, FALSE, lSample);
ptr = (unsigned char *)lpvBuffer;
y = lHeight;
do {
x = lWidth;
do {
lWhiteTotal += (long)*ptr++;
} while(--x);
ptr += lModulo;
} while(--y);
#else
streamGetFrame(lpInputBuffer, lActualBytes, FALSE, FALSE, lSample);
ptr = (unsigned char *)lpvBuffer;
y = lHeight;
do {
x = lWidth;
do {
lWhiteTotal += (long)*ptr++;
lWhiteTotal ^= 0xAAAAAAAA;
} while(--x);
ptr += lModulo;
} while(--y);
pFrameSums[lSample - lSampleFirst] = lWhiteTotal;
#endif
// if (lBlackTotal == lWhiteTotal)
// key_flags[(lSample - lSampleFirst)>>3] |= 1<<((lSample-lSampleFirst)&7);
rekey_error:
++lSample;
// pd.advance(lSample - lSampleFirst);
// pd.check();
}
lSample = lSampleFirst;
do {
long lBlackTotal=0, lWhiteTotal=0;
long x, y;
const long lWidth = (bmihDecompressedFormat->biWidth * bmihDecompressedFormat->biBitCount + 7)/8;
const long lModulo = (4-lWidth)&3;
const long lHeight = bmihDecompressedFormat->biHeight;
unsigned char *ptr;
_RPT1(0,"Rekeying frame %ld\n", lSample);
err = _read(lSample, 1, lpInputBuffer, lMaxFrame, &lActualBytes, &lActualSamples);
if (err != AVIERR_OK)
// throw MyAVIError("VideoSourceAVI", err);
goto rekey_error2;
streamGetFrame(lpInputBuffer, lActualBytes, FALSE, FALSE, lSample);
ptr = (unsigned char *)lpvBuffer;
y = lHeight;
do {
x = lWidth;
do {
lWhiteTotal += (long)*ptr++;
lWhiteTotal ^= 0xAAAAAAAA;
} while(--x);
ptr += lModulo;
} while(--y);
if (lWhiteTotal == pFrameSums[lSample - lSampleFirst])
key_flags[(lSample - lSampleFirst)>>3] |= 1<<((lSample-lSampleFirst)&7);
rekey_error2:
if (lSample == lSampleFirst)
lSample = lSampleLast-1;
else
--lSample;
// pd.advance(lSampleLast*2 - (lSample+lSampleFirst));
// pd.check();
} while(lSample >= lSampleFirst+1);
streamEnd();
} catch(...) {
if (fStreamBegun) streamEnd();
delete[] lpInputBuffer;
delete[] pFrameSums;
throw;
}
delete[] lpInputBuffer;
delete[] pFrameSums;
}
int VideoSourceAVI::_read(LONG lStart, LONG lCount, LPVOID lpBuffer, LONG cbBuffer, LONG *lBytesRead, LONG *lSamplesRead) {
IAVIReadStream *pSource = pAVIStream;
bool phase = (lStart - lSampleFirst)&1;
if (mjpeg_mode == IFMODE_SPLIT1 || mjpeg_mode == IFMODE_SPLIT2)
lStart = lSampleFirst + (lStart - lSampleFirst)/2;
// 如果被条纹化,那么寻找正确的条纹
if (stripesys) {
AVIStripeIndexEntry *asie;
long offset;
if (!(asie = stripe_index->lookup(lStart)))
return AVIERR_FILEREAD;
offset = lStart - asie->lSampleFirst;
if (lCount > asie->lSampleCount-offset)
lCount = asie->lSampleCount-offset;
if (!stripe_streams[asie->lStripe])
return AVIERR_FILEREAD;
pSource = stripe_streams[asie->lStripe];
lStart = asie->lStripeSample + offset;
}
// 是否为MJPEG修正模式?
if (mjpeg_mode) {
int res;
LONG lBytes, lSamples;
long lRealSample = lStart;
long lOffset, lLength;
// 是否和上次输入的sample相同?
if (lStart == mjpeg_last) {
lBytes = mjpeg_last_size;
res = AVIERR_OK;
} else {
// 把sample读入内存。如果不知道放入的地址或者已经知道
// 条纹在那里,仅仅返回sample的大小
if (lpBuffer || mjpeg_splits[lStart - lSampleFirst]<0) {
mjpeg_last = -1;
if (mjpeg_reorder_buffer_size)
res = pSource->Read(lStart, 1, mjpeg_reorder_buffer, mjpeg_reorder_buffer_size, &lBytes, &lSamples);
if (res == AVIERR_BUFFERTOOSMALL || !mjpeg_reorder_buffer_size) {
void *new_buffer;
int new_size;
res = pSource->Read(lStart, 1, NULL, 0, &lBytes, &lSamples);
if (res == AVIERR_OK) {
_ASSERT(lBytes != 0);
new_size = (lBytes + 4095) & -4096;
new_buffer = reallocmem(mjpeg_reorder_buffer, new_size);
if (!new_buffer)
return AVIERR_MEMORY;
mjpeg_reorder_buffer = new_buffer;
mjpeg_reorder_buffer_size = new_size;
res = pSource->Read(lStart, 1, mjpeg_reorder_buffer, mjpeg_reorder_buffer_size, &lBytes, &lSamples);
}
}
if (res == AVIERR_OK) {
mjpeg_last = lStart;
mjpeg_last_size = lBytes;
}
} else
res = pSource->Read(lStart, 1, NULL, 0, &lBytes, &lSamples);
}
if (res != AVIERR_OK) {
if (lBytesRead)
*lBytesRead = 0;
if (lSamplesRead)
*lSamplesRead = 0;
return res;
} else if (!lBytes) {
if (lBytesRead)
*lBytesRead = 0;
if (lSamplesRead)
*lSamplesRead = 1;
return AVIERR_OK;
}
// 在sample中寻找SOI标记
lOffset = 0;
lLength = lBytes;
{
int i;
// 是否已经知道条纹在哪里?
if (mjpeg_splits[lStart-lSampleFirst]<0) {
for(i=2; i<lBytes-2; i++)
if (((unsigned char *)mjpeg_reorder_buffer)[i] == (unsigned char)0xFF
&& ((unsigned char *)mjpeg_reorder_buffer)[i+1] == (unsigned char)0xD8)
break;
mjpeg_splits[lStart - lSampleFirst] = i;
} else {
i = mjpeg_splits[lStart - lSampleFirst];
}
if (i<lBytes-2) {
if (mjpeg_mode != IFMODE_SWAP) {
switch(mjpeg_mode) {
case IFMODE_SPLIT2:
phase = !phase;
break;
case IFMODE_DISCARD1:
phase = false;
break;
case IFMODE_DISCARD2:
phase = true;
break;
}
if (phase) {
lOffset = i;
lLength = lBytes - i;
} else {
lOffset = 0;
lLength = i;
}
} else
lOffset = i;
}
}
if (lpBuffer) {
if (lSamplesRead)
*lSamplesRead = 1;
if (lBytesRead)
*lBytesRead = lLength;
if (cbBuffer < lLength)
return AVIERR_BUFFERTOOSMALL;
if (mjpeg_mode == IFMODE_SWAP) {
char *pp1 = (char *)lpBuffer;
char *pp2 = (char *)lpBuffer + (lBytes - lOffset);
memcpy(pp1, (char *)mjpeg_reorder_buffer+lOffset, lBytes - lOffset);
if (lOffset)
memcpy(pp2, mjpeg_reorder_buffer, lOffset);
if (((short *)pp1)[1]==(short)0xE0FF)
pp1[10] = 1;
if (((short *)pp2)[1]==(short)0xE0FF)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -