📄 videosource.cpp
字号:
// VirtualDub - Video processing and capture application
// Copyright (C) 1998-2001 Avery Lee
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include <crtdbg.h>
#include <stdio.h>
#include <windows.h>
#include <vfw.h>
#include "VideoSource.h"
//#include "VBitmap.h"
#include "AVIStripeSystem.h"
//#include "ProgressDialog.h"
//#include "MJPEGDecoder.h"
//#include "crash.h"
#include "error.h"
#include "misc.h"
#include "oshelper.h"
//#include "helpfile.h"
#include "resourceVD.h"
///////////////////////////
extern const char *LookupVideoCodec(FOURCC);
extern HINSTANCE g_hInst;
extern HWND g_hWnd;
///////////////////////////
const char g_szNoMPEG4Test[]="No MPEG-4 Test";
static BOOL CALLBACK MP4CodecWarningDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDOK:
// HelpContext(hdlg, IDH_WARN_MPEG4);
MessageBox( NULL,"WarningMPEG4", "WarningMPEG4", MB_OK );
case IDCANCEL:
if (IsDlgButtonChecked(hdlg, IDC_NOMORE))
SetConfigDword(NULL, g_szNoMPEG4Test, 1);
EndDialog(hdlg, 0);
break;
}
break;
}
return FALSE;
}
static bool CheckMPEG4Codec(HIC hic, bool isV3) {
char frame[0x380];
BITMAPINFOHEADER bih;
DWORD dw;
if (QueryConfigDword(NULL, g_szNoMPEG4Test, &dw) && dw)
return true;
// Form a completely black frame if it's V3.
bih.biSize = 40;
bih.biWidth = 320;
bih.biHeight = 240;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = '24PM';
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
if (isV3) {
int i;
frame[0] = (char)0x3f;
frame[1] = (char)0x71;
frame[2] = (char)0x1b;
frame[3] = (char)0x7c;
for(i=4; i<0x179; i+=5) {
frame[i+0] = (char)0x2f;
frame[i+1] = (char)0x0b;
frame[i+2] = (char)0xc2;
frame[i+3] = (char)0xf0;
frame[i+4] = (char)0xbc;
}
frame[0x179] = (char)0xf0;
frame[0x17a] = (char)0xb8;
frame[0x17b] = (char)0x01;
bih.biCompression = '34PM';
bih.biSizeImage = 0x17c;
}
// Attempt to decompress.
HANDLE h;
h = ICImageDecompress(hic, 0, (BITMAPINFO *)&bih, frame, NULL);
// if (!h)
// DialogBox(g_hInst, MAKEINTRESOURCE(IDD_WARN_MPEG4), g_hWnd, MP4CodecWarningDlgProc);
// else
// GlobalFree(h);
if (h) {
GlobalFree(h);
return true;
} else {
return false;
}
}
///////////////////////////
VideoSource::VideoSource() {
lpvBuffer = NULL;
hBufferObject = NULL;
bmihDecompressedFormat = NULL;
}
VideoSource::~VideoSource() {
freemem(bmihDecompressedFormat);
FreeFrameBuffer();
}
void *VideoSource::AllocFrameBuffer(long size) {
hBufferObject = CreateFileMapping(
(HANDLE)0xFFFFFFFF,
NULL,
PAGE_READWRITE,
0,
size,
NULL);
if (!hBufferObject) return NULL;
lBufferOffset = 0;
lpvBuffer = MapViewOfFile(hBufferObject, FILE_MAP_ALL_ACCESS, 0, lBufferOffset, size);
if (!lpvBuffer) {
CloseHandle(hBufferObject);
hBufferObject = NULL;
}
return lpvBuffer;
}
void VideoSource::FreeFrameBuffer() {
if (hBufferObject) {
if (lpvBuffer)
UnmapViewOfFile(lpvBuffer);
CloseHandle(hBufferObject);
} else
freemem(lpvBuffer);
lpvBuffer = NULL;
hBufferObject = NULL;
}
bool VideoSource::setDecompressedFormat(int depth) {
memcpy(bmihDecompressedFormat, getImageFormat(), getFormatLen());
bmihDecompressedFormat->biSize = sizeof(BITMAPINFOHEADER);
bmihDecompressedFormat->biPlanes = 1;
bmihDecompressedFormat->biBitCount = depth;
bmihDecompressedFormat->biCompression = BI_RGB;
bmihDecompressedFormat->biSizeImage = ((bmihDecompressedFormat->biWidth * depth + 31)/32)*4*bmihDecompressedFormat->biHeight;
if (depth>8) {
bmihDecompressedFormat->biClrUsed = 0;
bmihDecompressedFormat->biClrImportant = 0;
}
invalidateFrameBuffer();
return true;
}
bool VideoSource::setDecompressedFormat(BITMAPINFOHEADER *pbih) {
if (pbih->biCompression == BI_RGB) {
setDecompressedFormat(pbih->biBitCount);
return true;
}
return false;
}
void VideoSource::streamBegin(bool) {
stream_current_frame = -1;
}
void VideoSource::streamSetDesiredFrame(long frame_num) {
long key;
key = isKey(frame_num) ? frame_num : prevKey(frame_num);
if (key<0) key = lSampleFirst;
stream_desired_frame = frame_num;
if (stream_current_frame<key || stream_current_frame>frame_num)
stream_current_frame = key-1;
}
long VideoSource::streamGetNextRequiredFrame(BOOL *is_preroll) {
if (stream_current_frame == stream_desired_frame) {
*is_preroll = FALSE;
return -1;
}
*is_preroll = (++stream_current_frame != stream_desired_frame);
return stream_current_frame;
}
int VideoSource::streamGetRequiredCount(long *pSize) {
if (pSize) {
long current = stream_current_frame;
long size = 0, onesize;
long samp;
while(current < stream_desired_frame) {
if (AVIERR_OK == read(current, 1, NULL, NULL, &onesize, &samp))
size += onesize;
++current;
}
*pSize = size;
}
return stream_desired_frame - stream_current_frame;
}
void VideoSource::invalidateFrameBuffer() {
}
bool VideoSource::isKeyframeOnly() {
return false;
}
bool VideoSource::isType1() {
return false;
}
///////////////////////////
VideoSourceAVI::VideoSourceAVI(IAVIReadHandler *pAVI, AVIStripeSystem *stripesys, IAVIReadHandler **stripe_files, bool use_internal, int mjpeg_mode, FOURCC fccForceVideo, FOURCC fccForceVideoHandler) {
pAVIFile = pAVI;
pAVIStream = NULL;
lpvBuffer = NULL;
hicDecomp = NULL;
bmihTemp = NULL;
key_flags = NULL;
mjpeg_reorder_buffer = NULL;
mjpeg_reorder_buffer_size = 0;
mjpeg_splits = NULL;
mjpeg_last = -1;
this->fccForceVideo = fccForceVideo;
this->fccForceVideoHandler = fccForceVideoHandler;
hbmLame = NULL;
fUseGDI = false;
// striping...
stripe_streams = NULL;
stripe_index = NULL;
this->stripesys = stripesys;
this->stripe_files = stripe_files;
this->use_internal = use_internal;
this->mjpeg_mode = mjpeg_mode;
mdec = NULL;
try {
_construct();
} catch(...) {
_destruct();
throw;
}
}
void VideoSourceAVI::_destruct() {
delete stripe_index;
if (stripe_streams) {
int i;
for(i=0; i<stripe_count; i++)
if (stripe_streams[i])
delete stripe_streams[i];
delete stripe_streams;
}
if (bmihTemp) freemem(bmihTemp);
if (hicDecomp) ICClose(hicDecomp);
if (pAVIStream) delete pAVIStream;
delete mdec;
freemem(mjpeg_reorder_buffer);
mjpeg_reorder_buffer = NULL;
delete[] mjpeg_splits;
mjpeg_splits = NULL;
delete[] key_flags; key_flags = NULL;
if (hbmLame) {
DeleteObject(hbmLame);
hbmLame = NULL;
}
}
VideoSourceAVI::~VideoSourceAVI() {
_destruct();
}
void VideoSourceAVI::_construct() {
LONG format_len;
BITMAPINFOHEADER *bmih;
bool is_mjpeg, is_dib;
// 寻找标准的vids流
bIsType1 = false;
pAVIStream = pAVIFile->GetStream(streamtypeVIDEO, 0);
if (!pAVIStream) {
pAVIStream = pAVIFile->GetStream('svai', 0);
if (!pAVIStream)
throw MyError("No video stream found.");
bIsType1 = true;
}
if (pAVIStream->Info(&streamInfo, sizeof streamInfo))
throw MyError("Error obtaining video stream info.");
// ADDITION FOR STRIPED AVI SUPPORT:
//
// If this is an index for a stripe system, then the video stream will have
// 'VDST' as its fccHandler and video compression. This will probably
// correspond to the "VDub Frameserver" compressor, but since VirtualDub can
// connect to its own frameservers more efficiently though the AVIFile
// interface, it makes sense to open striped files in native mode.
//
// For this to work, we must have been sent the striping specs beforehand,
// or else we won't be able to open the stripes.
if (streamInfo.fccHandler == 'TSDV') {
int i;
if (!stripesys)
throw MyError("AVI file is striped - must be opened with stripe definition file.");
// 为条纹流表分配内存空间
stripe_count = stripesys->getStripeCount();
if (!(stripe_streams = new IAVIReadStream *[stripe_count]))
throw MyMemoryError();
for(i=0; i<stripe_count; i++)
stripe_streams[i] = NULL;
format_stream = NULL;
for(i=0; i<stripe_count; i++) {
if (stripesys->getStripeInfo(i)->isVideo()) {
stripe_streams[i] = stripe_files[i]->GetStream(streamtypeVIDEO, 0);
if (!stripe_streams[i])
throw MyError("Striping: cannot open video stream for stripe #%d", i+1);
if (!format_stream) format_stream = stripe_streams[i];
}
}
if (!format_stream)
throw MyError("Striping: No video stripes found!");
if (format_stream->Info(&streamInfo, sizeof streamInfo))
throw MyError("Error obtaining video stream info from first video stripe.");
// 初始化下标
if (!(stripe_index = new AVIStripeIndexLookup(pAVIStream)))
throw MyMemoryError();
} else {
if (stripesys)
throw MyError("This is not a striped AVI file.");
format_stream = pAVIStream;
}
// 读视频格式。如果遇到条纹,那么条纹的引索有一个虚拟格式
// 所以必须从一个视频条纹得到它相应的格式。如果是格式是
// type-1 DV,继续要虚拟之。
if (bIsType1) {
format_len = sizeof(BITMAPINFOHEADER);
if (!(bmih = (BITMAPINFOHEADER *)allocFormat(format_len))) throw MyMemoryError();
bmih->biSize = sizeof(BITMAPINFOHEADER);
bmih->biWidth = 720;
if (streamInfo.dwRate > streamInfo.dwScale*26i64)
bmih->biHeight = 480;
else
bmih->biHeight = 576;
bmih->biPlanes = 1;
bmih->biBitCount = 24;
bmih->biCompression = 'dsvd';
bmih->biSizeImage = streamInfo.dwSuggestedBufferSize;
bmih->biXPelsPerMeter = 0;
bmih->biYPelsPerMeter = 0;
bmih->biClrUsed = 0;
bmih->biClrImportant = 0;
} else {
format_stream->FormatSize(0, &format_len);
if (!(bmih = (BITMAPINFOHEADER *)allocFormat(format_len))) throw MyMemoryError();
if (format_stream->ReadFormat(0, getFormat(), &format_len))
throw MyError("Error obtaining video stream format.");
}
if (!(bmihTemp = (BITMAPINFOHEADER *)allocmem(format_len))) throw MyMemoryError();
if (!(bmihDecompressedFormat = (BITMAPINFOHEADER *)allocmem(format_len))) throw MyMemoryError();
// RGB8/16/24/32和YUY2颜色空间可以被处理
is_dib = (bmih->biCompression == BI_RGB) || (bmih->biCompression == '2YUY');
// 如果需要,强制转换视频格式
if (fccForceVideo)
getImageFormat()->biCompression = fccForceVideo;
if (fccForceVideoHandler)
streamInfo.fccHandler = fccForceVideoHandler;
is_mjpeg = isEqualFOURCC(bmih->biCompression, 'GPJM')
|| isEqualFOURCC(fccForceVideo, 'GPJM')
|| isEqualFOURCC(bmih->biCompression, '1bmd')
|| isEqualFOURCC(fccForceVideo, '1bmd');
// 如果格式为MJPEG,检查是否需要修改输出格式或者流信息
lSampleFirst = pAVIStream->Start();
lSampleLast = pAVIStream->End();
if (is_mjpeg) {
BITMAPINFOHEADER *pbih = getImageFormat();
if (mjpeg_mode && mjpeg_mode != IFMODE_SWAP && pbih->biHeight > 288) {
pbih->biHeight /= 2;
if (mjpeg_mode == IFMODE_SPLIT1 || mjpeg_mode == IFMODE_SPLIT2) {
streamInfo.dwRate *= 2;
streamInfo.dwLength *= 2;
lSampleLast = lSampleLast*2 - lSampleFirst;
}
}
if (mjpeg_mode) {
if (!(mjpeg_splits = new long[lSampleLast - lSampleFirst]))
throw MyMemoryError();
for(int i=0; i<lSampleLast-lSampleFirst; i++)
mjpeg_splits[i] = -1;
}
} else
mjpeg_mode = 0;
memcpy(bmihTemp, getFormat(), format_len);
// 分配帧缓存
if (!AllocFrameBuffer(bmih->biWidth * 4 * bmih->biHeight + 4))
throw MyMemoryError();
// 取得解码器
//
// 'DIB '是标准的解码后的AVI文件标记值。不过有一些条纹程序使用
// (null) 和 'RAW '
hicDecomp = NULL;
if (bmih->biCompression == BI_BITFIELDS || bmih->biCompression == BI_RLE8 || bmih->biCompression == BI_RLE4
|| (bmih->biCompression == BI_RGB && bmih->biBitCount<16 && bmih->biBitCount != 8)) {
// 如果是冷僻的格式,用GDI处理
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -