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

📄 store.c

📁 DVD转换到AVI的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 
 *	Copyright (C) Chia-chen Kuo - Jan 2001
 *
 *  This file is part of DVD2AVI, a free MPEG-2 decoder
 *	
 *  DVD2AVI 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, or (at your option)
 *  any later version.
 *   
 *  DVD2AVI 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 GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 */

#include "global.h"

#define MAX_AVI_SIZE	2073600000

__forceinline static void Store_RGB24(unsigned char *src[], DWORD frame);
__forceinline static void Store_YUY2(unsigned char *src[], DWORD frame);

static void Luminance_Filter(unsigned char *src, unsigned char *dst);
static void conv420to422(unsigned char *src, unsigned char *dst);
static void conv422to444(unsigned char *src, unsigned char *dst);
static void conv444toRGB24odd(unsigned char *py, unsigned char *pu, unsigned char *pv, unsigned char *dst);
static void conv444toRGB24even(unsigned char *py, unsigned char *pu, unsigned char *pv, unsigned char *dst);
static void Flush_RGB24();
static void conv422toyuy2odd(unsigned char *py, unsigned char *pu, unsigned char *pv, unsigned char *dst);
static void conv422toyuy2even(unsigned char *py, unsigned char *pu, unsigned char *pv, unsigned char *dst);
static void Flush_YUY2();
static void AVIKill();

PAVIFILE pfile;
PAVISTREAM ps, psCompressed;
AVICOMPRESSOPTIONS opts;
LPAVICOMPRESSOPTIONS lpopts = &opts;
AVISTREAMINFO strinfo;
ICCOMPRESSFRAMES iccf;
COMPVARS compvars;
PCOMPVARS pcompvars = &compvars;

static unsigned char *y444;
static int AVI_Init, avi_size, avi_count, frame_count;
static int TFF, RFF, TFB, BFB, playback, Old_Playback, frame_size, frame_type;
static char VideoOut[_MAX_PATH];

static char *FrameType[3] = {
	"", "Interlaced", "Progressive"
};

static const __int64 mmmask_0001 = 0x0001000100010001;
static const __int64 mmmask_0002 = 0x0002000200020002;
static const __int64 mmmask_0003 = 0x0003000300030003;
static const __int64 mmmask_0004 = 0x0004000400040004;
static const __int64 mmmask_0005 = 0x0005000500050005;
static const __int64 mmmask_0007 = 0x0007000700070007;
static const __int64 mmmask_0064 = 0x0040004000400040;
static const __int64 mmmask_0128 = 0x0080008000800080;
static const __int64 mmmask_cbu = 0x0000408D0000408D;
static const __int64 mmmask_cgu_cgv = 0xF377E5FCF377E5FC;
static const __int64 mmmask_crv = 0x0000331300003313;

void Write_Frame(unsigned char *src[], D2VData d2v, DWORD frame)
{
	int i, repeat;

	if (Fault_Flag)
	{
		if (Fault_Flag < CRITICAL_ERROR_LEVEL)
		{
			SetDlgItemText(hDlg, IDC_DEBUG, "V.E.");
			Fault_Flag = 0;		// Fault Tolerance
		}
		else
		{
			if (AVI_Flag)
				AVIKill();
			ThreadKill();
		}
	}

	frame_type = d2v.pf;
	TFF = d2v.trf>>1;
	RFF = d2v.trf & 0x01;

	if (!frame)
	{
		AVI_Init = 1; TFB = BFB = 0; Old_Playback = 0;
		frame_size = 0; avi_size = 0; avi_count = 1; frame_count = 0; playback = 0;

		if (process.locate==LOCATE_RIP && FO_Flag==FO_SWAP)
		{
			if (TFF)
				BFB = 1;
			else
				TFB = 1;

			ZeroMemory(rgb24, Coded_Picture_Width*Coded_Picture_Height*3);
			for (i=0; i<Coded_Picture_Width*Coded_Picture_Height*2; i += 2)
			{
				yuy2[i] = 0;
				yuy2[i+1] = 128;
			}
		}

		if (FO_Flag!=FO_FILM)
		{
			if ((TFF && FO_Flag!=FO_SWAP) || (!TFF && FO_Flag==FO_SWAP))
				SetDlgItemText(hDlg, IDC_DEBUG, "T");
			else
				SetDlgItemText(hDlg, IDC_DEBUG, "B");
		}
	}

	repeat = DetectVideoType(frame, d2v.trf);

	if (FO_Flag!=FO_FILM || repeat)
	{
		if (Store_Flag==STORE_YUY2)
			Store_YUY2(src, frame);
		else
			Store_RGB24(src, frame);
	}

	if (FO_Flag==FO_FILM && repeat==2)
	{
		if (Store_Flag==STORE_YUY2)
			Store_YUY2(src, frame);
		else
			Store_RGB24(src, frame);
	}

	__asm emms;

	if (Statistics_Flag && process.locate==LOCATE_RIP)
	{
		sprintf(szBuffer, "%s", FrameType[frame_type+1]);
		SetDlgItemText(hDlg, IDC_FRAME_TYPE, szBuffer);

		sprintf(szBuffer, "%d", frame+1);
		SetDlgItemText(hDlg, IDC_CODED_NUMBER, szBuffer);

		sprintf(szBuffer, "%d", playback);
		SetDlgItemText(hDlg, IDC_PLAYBACK_NUMBER, szBuffer);

		if (AVI_Flag)
		{
			sprintf(szBuffer, "%d", avi_count-1);
			SetDlgItemText(hDlg, IDC_FILE, szBuffer);
	
			sprintf(szBuffer, "%d MB", avi_size>>20);
			SetDlgItemText(hDlg, IDC_FILE_SIZE, szBuffer);
		}

		if ((frame & 63) == 63)
		{
			process.ed = timeGetTime();
			sprintf(szBuffer, "%.2f FPS", 1000.0*(playback-1)/(process.ed-process.op+1));
			SetDlgItemText(hDlg, IDC_FPS, szBuffer);

			SendDlgItemMessage(hDlg, IDC_PROGRESS, PBM_SETPOS, (int)(Bitrate_Meter*Frame_Rate/(playback-Old_Playback))>>7, 0);

			Bitrate_Meter = 0;
			Old_Playback = playback;
		}
	}

	if (AVI_Flag && avi_size>=MAX_AVI_SIZE)
		AVIKill();
}

static void Store_RGB24(unsigned char *src[], DWORD frame)
{
	// store AVI
	if (AVI_Flag && AVI_Init)
	{
		if (!frame)
		{
			compvars.cbSize = sizeof(compvars);

			if (!ICCompressorChoose(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME,
				lpbirgb, NULL, pcompvars, NULL))
				ThreadKill();

			// set AVI header
			ZeroMemory(&strinfo, sizeof(AVISTREAMINFO));
			strinfo.fccType					= streamtypeVIDEO;
			strinfo.fccHandler				= compvars.fccHandler;
			strinfo.dwQuality				= -1;
			strinfo.dwSuggestedBufferSize	= birgb.biSizeImage;
			strinfo.dwScale	= 1000;
			strinfo.dwRate = (unsigned int)((FO_Flag==FO_FILM) ? frame_rate*800 : frame_rate*1000);

			// set AVI save options
			opts.cbFormat = sizeof(birgb);
			opts.fccType = streamtypeVIDEO;
			opts.fccHandler = compvars.fccHandler;
			opts.dwKeyFrameEvery = compvars.lKey;
			opts.dwQuality = compvars.lQ;
			opts.dwBytesPerSecond = compvars.lDataRate<<10;
			opts.dwFlags = AVICOMPRESSF_VALID | AVICOMPRESSF_KEYFRAMES | AVICOMPRESSF_DATARATE;
			opts.dwInterleaveEvery = 0;
			opts.lpFormat = lpbirgb;
			opts.cbParms = compvars.cbState;
			opts.lpParms = compvars.lpState;
		}

		AVI_Init = 0; avi_size = 0;
		AVIFileInit();

		sprintf(VideoOut, "%s %02d.avi", szOutput, avi_count++);

		if (AVIFileOpen(&pfile, VideoOut, OF_WRITE | OF_CREATE, NULL) != AVIERR_OK)
		{
			AVIKill();
			ThreadKill();
		}

		if (AVIFileCreateStream(pfile, &ps, &strinfo) != AVIERR_OK)
		{
			AVIKill();
			ThreadKill();
		}

		if (AVIMakeCompressedStream(&psCompressed, ps, lpopts, NULL) != AVIERR_OK)
		{
			AVIKill();
			ThreadKill();
		}

		if (AVIStreamSetFormat(psCompressed, 0, lpbirgb, birgb.biSize) != AVIERR_OK)
		{
			AVIKill();
			ThreadKill();
		}
	}

	if (chroma_format==CHROMA420)
	{
		conv420to422(src[1], u422);
		conv420to422(src[2], v422);

		conv422to444(u422, u444);
		conv422to444(v422, v444);
	}
	else
	{
		conv422to444(src[1], u444);
		conv422to444(src[2], v444);
	}

	if (Luminance_Flag)
	{
		Luminance_Filter(src[0], lum);
		y444 = lum;
	}
	else
		y444 = src[0];

	if (BFB)
	{
		conv444toRGB24odd(y444, u444, v444, rgb24);
		Flush_RGB24();
		conv444toRGB24even(y444, u444, v444, rgb24);
		Flush_RGB24();
	}
	else
	{
		conv444toRGB24even(y444, u444, v444, rgb24);
		Flush_RGB24();
		conv444toRGB24odd(y444, u444, v444, rgb24);
		Flush_RGB24();
	}

	if (FO_Flag!=FO_FILM && RFF)
		if (TFF)
		{
			conv444toRGB24odd(y444, u444, v444, rgb24);
			Flush_RGB24();
		}
		else
		{
			conv444toRGB24even(y444, u444, v444, rgb24);
			Flush_RGB24();
		}
}

static void Flush_RGB24()
{
	if (TFB & BFB)
	{
		if (AVI_Flag)
		{
			__asm emms;

			if (AVIStreamWrite(psCompressed, frame_count++, 1, rgb24,
				birgb.biSizeImage, 0, NULL, &frame_size) != AVIERR_OK)
			{
				AVIKill();
				ThreadKill();
			}

			avi_size += frame_size;
		}

		if (Display_Flag)
			RenderRGB24();

		playback++;
		TFB = BFB = 0;
	}
}

//--------------------------------------------------------------------------------------

static void Store_YUY2(unsigned char *src[], DWORD frame)
{
	// Save AVI
	if (AVI_Flag && AVI_Init)
	{
		if (!frame)
		{
			compvars.cbSize = sizeof(compvars);

			if (!ICCompressorChoose(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME,
				lpbiyuv, NULL, pcompvars, NULL))
				ThreadKill();

			// set AVI header
			ZeroMemory(&strinfo, sizeof(AVISTREAMINFO));
			strinfo.fccType					= streamtypeVIDEO;
			strinfo.fccHandler				= compvars.fccHandler;
			strinfo.dwQuality				= -1;
			strinfo.dwSuggestedBufferSize	= biyuv.biSizeImage;
			strinfo.dwScale	= 1000;
			strinfo.dwRate = (unsigned int)((FO_Flag==FO_FILM) ? frame_rate*800 : frame_rate*1000);

			// set AVI save options
			opts.cbFormat = sizeof(biyuv);
			opts.fccType = streamtypeVIDEO;
			opts.fccHandler = compvars.fccHandler;
			opts.dwKeyFrameEvery = compvars.lKey;
			opts.dwQuality = compvars.lQ;
			opts.dwBytesPerSecond = compvars.lDataRate<<10;
			opts.dwFlags = AVICOMPRESSF_VALID | AVICOMPRESSF_KEYFRAMES | AVICOMPRESSF_DATARATE;
			opts.dwInterleaveEvery = 0;
			opts.lpFormat = lpbiyuv;
			opts.cbParms = compvars.cbState;
			opts.lpParms = compvars.lpState;

			iccf.dwRate = strinfo.dwRate;
			iccf.dwScale = strinfo.dwScale;
			iccf.lQuality = compvars.lQ;
			iccf.lDataRate = compvars.lDataRate<<10;
			iccf.lKeyRate = compvars.lKey;

			ICSendMessage(compvars.hic, ICM_COMPRESS_FRAMES_INFO, (WPARAM)&iccf, (DWORD)sizeof(ICCOMPRESSFRAMES));
		}

		AVI_Init = 0; avi_size = 0;
		AVIFileInit();

		sprintf(VideoOut, "%s %02d.avi", szOutput, avi_count++);

		if (AVIFileOpen(&pfile, VideoOut, OF_WRITE | OF_CREATE, NULL) != AVIERR_OK)
		{
			AVIKill();
			ThreadKill();
		}

		if (AVIFileCreateStream(pfile, &ps, &strinfo) != AVIERR_OK)
		{
			AVIKill();
			ThreadKill();
		}

		if (AVIMakeCompressedStream(&psCompressed, ps, lpopts, NULL) != AVIERR_OK)
		{
			AVIKill();
			ThreadKill();
		}

		if (AVIStreamSetFormat(psCompressed, 0, lpbirgb, birgb.biSize) != AVIERR_OK)
		{
			AVIKill();
			ThreadKill();
		}

		if (!frame && !ICSeqCompressFrameStart(pcompvars, (LPBITMAPINFO)lpbiyuv))
		{
			AVIKill();
			ThreadKill();
		}
	}

	if (chroma_format==CHROMA420)
	{
		conv420to422(src[1], u422);
		conv420to422(src[2], v422);
	}
	else
	{
		u422 = src[1];
		v422 = src[2];
	}

	if (Luminance_Flag)
	{
		Luminance_Filter(src[0], lum);
		y444 = lum;
	}
	else
		y444 = src[0];

	if (BFB)
	{
		conv422toyuy2odd(y444, u422, v422, yuy2);
		Flush_YUY2();
		conv422toyuy2even(y444, u422, v422, yuy2);
		Flush_YUY2();
	}
	else
	{
		conv422toyuy2even(y444, u422, v422, yuy2);
		Flush_YUY2();

		conv422toyuy2odd(y444, u422, v422, yuy2);
		Flush_YUY2();
	}

	if (FO_Flag!=FO_FILM && RFF)
		if (TFF)
		{
			conv422toyuy2odd(y444, u422, v422, yuy2);
			Flush_YUY2();
		}
		else
		{
			conv422toyuy2even(y444, u422, v422, yuy2);
			Flush_YUY2();
		}
}

static void Flush_YUY2()
{
	void *yuy2c; int key_flag, yuy2c_size;

	if (TFB & BFB)
	{
		if (AVI_Flag)
		{
			__asm emms;

			if ((yuy2c = ICSeqCompressFrame(pcompvars, 0, yuy2, &key_flag, &yuy2c_size)) == NULL)
			{
				AVIKill();
				ThreadKill();
			}

			if (AVIStreamWrite(ps, frame_count++, 1, yuy2c, yuy2c_size,
				key_flag ? AVIIF_KEYFRAME : 0, NULL, &frame_size) != AVIERR_OK)
			{
				AVIKill();
				ThreadKill();
			}

			avi_size += frame_size;
		}

		if (DDOverlay_Flag && Display_Flag)
			RenderYUY2();

		playback++;
		TFB = BFB = 0;
	}
}

//-------------------------------------------------------------------------------------

static void Luminance_Filter(unsigned char *src, unsigned char *dst)
{
	int AREA = Coded_Picture_Width * Coded_Picture_Height;

	__asm
	{
		mov			eax, [src]
		mov			ebx, [dst]
		mov			esi, 0x00
		mov			edi, [AREA]
		pxor		mm0, mm0
		movq		mm5, [LumOffsetMask]
		movq		mm6, [LumGainMask]
		movq		mm7, [mmmask_0064]

lumconv:
		movq		mm1, [eax+esi]
		movq		mm2, mm1

		punpcklbw	mm1, mm0
		punpckhbw	mm2, mm0

		pmullw		mm1, mm6
		pmullw		mm2, mm6

		paddw		mm1, mm7
		paddw		mm2, mm7

		psrlw		mm1, 7
		psrlw		mm2, 7

		paddw		mm1, mm5
		paddw		mm2, mm5

		packuswb	mm1, mm0
		packuswb	mm2, mm0

		add			esi, 0x08
		cmp			esi, edi
		movq		[ebx+esi-8], mm1
		movq		[ebx+esi-4], mm2
		jl			lumconv
	}
}

static void conv422to444(unsigned char *src, unsigned char *dst)
{
	int RIGHT_BOUND = (Coded_Picture_Width>>1) - 8;
	int SRC_STRIDE = Coded_Picture_Width>>1;

	__asm
	{
		mov			eax, [src]
		mov			ebx, [dst]
		mov			edi, [Coded_Picture_Height]

		movq		mm1, [mmmask_0001]
		pxor		mm0, mm0

convyuv444init:
		movq		mm7, [eax]
		mov			esi, 0x00

convyuv444:
		movq		mm2, mm7
		movq		mm7, [eax+esi+8]
		movq		mm3, mm2
		movq		mm4, mm7

		psrlq		mm3, 8
		psllq		mm4, 56
		por			mm3, mm4

		movq		mm4, mm2
		movq		mm5, mm3

		punpcklbw	mm4, mm0
		punpcklbw	mm5, mm0

		movq		mm6, mm4
		paddusw		mm4, mm1
		paddusw		mm4, mm5
		psrlw		mm4, 1
		psllq		mm4, 8
		por			mm4, mm6

		punpckhbw	mm2, mm0
		punpckhbw	mm3, mm0

		movq		mm6, mm2
		paddusw		mm2, mm1
		paddusw		mm2, mm3

		movq		[ebx+esi*2], mm4

		psrlw		mm2, 1
		psllq		mm2, 8
		por			mm2, mm6

		add			esi, 0x08
		cmp			esi, [RIGHT_BOUND]
		movq		[ebx+esi*2-8], mm2
		jl			convyuv444

		movq		mm2, mm7
		punpcklbw	mm2, mm0
		movq		mm3, mm2

		psllq		mm2, 8
		por			mm2, mm3

		movq		[ebx+esi*2], mm2

		punpckhbw	mm7, mm0
		movq		mm6, mm7

		psllq		mm6, 8
		por			mm6, mm7

		movq		[ebx+esi*2+8], mm6

		add			eax, [SRC_STRIDE]		
		add			ebx, [Coded_Picture_Width]
		sub			edi, 0x01
		cmp			edi, 0x00
		jg			convyuv444init
	}
}

static void conv420to422(unsigned char *src, unsigned char *dst)
{
	int PROGRESSIVE_HEIGHT = (Coded_Picture_Height>>1) - 2;
	int INTERLACED_HEIGHT = (Coded_Picture_Height>>2) - 2;
	int HALF_WIDTH = Coded_Picture_Width>>1;
	int DOUBLE_WIDTH = Coded_Picture_Width<<1;

	if (frame_type)
	{
		__asm
		{
			mov			eax, [src]
			mov			ebx, [dst]
			mov			ecx, ebx
			add			ecx, [HALF_WIDTH]
			mov			esi, 0x00
			movq		mm3, [mmmask_0003]
			pxor		mm0, mm0
			movq		mm4, [mmmask_0002]

			mov			edx, eax
			add			edx, [HALF_WIDTH]
convyuv422topp:
			movd		mm1, [eax+esi]
			movd		mm2, [edx+esi]
			movd		[ebx+esi], mm1
			punpcklbw	mm1, mm0
			pmullw		mm1, mm3
			paddusw		mm1, mm4
			punpcklbw	mm2, mm0
			paddusw		mm2, mm1
			psrlw		mm2, 0x02
			packuswb	mm2, mm0

			add			esi, 0x04
			cmp			esi, [HALF_WIDTH]
			movd		[ecx+esi-4], mm2
			jl			convyuv422topp

			add			eax, [HALF_WIDTH]
			add			ebx, [Coded_Picture_Width]
			add			ecx, [Coded_Picture_Width]
			mov			esi, 0x00

			mov			edi, [PROGRESSIVE_HEIGHT]
convyuv422p:
			movd		mm1, [eax+esi]

			punpcklbw	mm1, mm0
			mov			edx, eax

			pmullw		mm1, mm3
			sub			edx, [HALF_WIDTH]

			movd		mm5, [edx+esi]
			movd		mm2, [edx+esi]

			punpcklbw	mm5, mm0
			punpcklbw	mm2, mm0
			paddusw		mm5, mm1
			paddusw		mm2, mm1
			paddusw		mm5, mm4
			paddusw		mm2, mm4
			psrlw		mm5, 0x02
			psrlw		mm2, 0x02
			packuswb	mm5, mm0
			packuswb	mm2, mm0

			mov			edx, eax
			add			edx, [HALF_WIDTH]
			add			esi, 0x04
			cmp			esi, [HALF_WIDTH]
			movd		[ebx+esi-4], mm5
			movd		[ecx+esi-4], mm2

			jl			convyuv422p

			add			eax, [HALF_WIDTH]
			add			ebx, [Coded_Picture_Width]
			add			ecx, [Coded_Picture_Width]
			mov			esi, 0x00
			sub			edi, 0x01
			cmp			edi, 0x00
			jg			convyuv422p

			mov			edx, eax
			sub			edx, [HALF_WIDTH]
convyuv422bottomp:
			movd		mm1, [eax+esi]
			movd		mm5, [edx+esi]
			punpcklbw	mm5, mm0
			movd		[ecx+esi], mm1

			punpcklbw	mm1, mm0
			pmullw		mm1, mm3
			paddusw		mm5, mm1
			paddusw		mm5, mm4
			psrlw		mm5, 0x02
			packuswb	mm5, mm0

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -