⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 videosource.cpp

📁 VC++视频开发实例集锦(包括“远程视频监控”"语音识别系统"等13个经典例子)
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//	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 + -