www.pudn.com > avi 到 mpeg 的转换程序及源代码.zip > READPIC.C


/* readpic.c, read source pictures from avi file          */ 
 
/* 
 * 4/4/97 - John Schlichther 
 * 
 * completely rewritten to create avi2mpg1 - avi to mpeg-1 encoder 
 * 
 *   Copyright (C) 1997  John Schlichther 
 * 
 *  7-19-97 - added support for 8 bit palletized video 
 *          - corrected chroma subsampling 
 *  7-30-97 - added support for faking corrupted frames (optional) 
 *          - used frame by frame data to determine horizontal and vertical 
 *            size of bitmap instead of AVIFILEINFO structure. Found at least one 
 *            avi which does not have this set properly. 
 *          - added support for 10, 12, and 15FPS video by frame replication 
 *          - adjusted RGB->YUV conversion 
 *  8-23-97 - center cropping region 
 * 10-19-97 - dynamically allocated space for U and V buffers 
 */ 

#include  
#include  

#include  
#include  
#include "global.h"
#include "video.h" 
 
unsigned int u, v, bpscanl, dib_offset, j, hblank, vblank, hcrop, vcrop, topblank; 
int x, y; 
float R, G, B; 
 
// RGB->YUV conversion constants 
 
const float RY = (77.0/256.0), GY = (150.0/256.0), BY = (29.0/256.0); 
const float RU = (-44.0/256.0), GU = (-87.0/256.0), BU = (131.0/256.0); 
const float RV = (131.0/256.0), GV = (-110.0/256.0), BV = (-21.0/256.0); 
 
void readframe(lCurFrame,frame)
unsigned char *frame[]; 
unsigned long	lCurFrame;
{
	unsigned char	*lpframeY, *lpframeU, *lpframeV; 
	unsigned int pixsz; 
	unsigned char *lpColor; 
	unsigned int palletized; 
 
	// now retrieve desired frame 
	// get pointer to bitmap 
	lpbi = AVIStreamGetFrame(pget, lCurFrame/frame_repl); 
	if(!lpbi && !fake_bad_frames) 
	{ 
		fprintf(stderr, "\ncould not retrieve video frame %i!\n", lCurFrame); 
		fprintf(stderr, "\npossibly corrupt avi file, try -e option."); 
		exit(-1); 
	} 
	else if(!lpbi && fake_bad_frames) 
	{ 
		lpbi = AVIStreamGetFrame(pget, last_good_video_frame); 
		bad_frame_count++; 
	} 
	else if(lpbi) 
	{ 
		last_good_video_frame = lCurFrame/frame_repl; 
	} 
 
	pixsz = lpbi->biBitCount; 
	if((pixsz!=8)&&(pixsz!=16)&&(pixsz!=24)&&(pixsz!=32)) 
	{ 
		fprintf(stderr, "\ncan only handle 8 bit palettized, or 16, 24, or 32 bit RGB video!"); 
		exit(-1); 
	} 
 
	if(pixsz==8) 
		palletized=1; 
	else 
		palletized=0; 
 
	// check for compression type of retrieved DIB 
 
	if (lpbi->biCompression != BI_RGB) // does not support BI_BITFIELDS 
	{ 
		fprintf(stderr, "\ncan not handle compressed DIBs from codec!"); 
		exit(-1); 
	} 
 
	// locate color table 
	lpColor = (unsigned char *)lpbi + lpbi->biSize;  
 
	// next, actual DIB 
	if(palletized) 
		dib_offset = sizeof(BITMAPINFOHEADER) + lpbi->biClrUsed * 4; 
	else 
		dib_offset = sizeof(BITMAPINFOHEADER); // offset past bitmap header 
	lpbitmp = (unsigned char *)lpbi + dib_offset; // pointer to actual bitmap 
 
	switch(pixsz) 
	{ 
	case 8: 
		bpscanl = (unsigned int)(((lpbi->biWidth + 3)>>2)<<2); 
		break; 
	case 16: 
		bpscanl = (unsigned int)(lpbi->biWidth * 2); 
		break; 
	case 24: 
		bpscanl = ((((unsigned int)lpbi->biWidth * 3 + 3)>>2)<<2); 
		break; 
	case 32: 
		bpscanl = (unsigned int)(lpbi->biWidth * 4); 
		break; 
	default: 
		fprintf(stderr, "\ninternal error: illegal pixsz value\n"); 
		exit(-1); // should never occur 
	} 
	// if frame width is less than output width, then there are blank pixels in output frame on left and right 
	if(width>lpbi->biWidth) 
		hblank = width - lpbi->biWidth; 
	else 
		hblank=0; 
 
	// similarily, if height is less than output, then there are blank lines at the top and bottom 
	if(height>lpbi->biHeight) 
		vblank = height - lpbi->biHeight; 
	else 
		vblank=0; 
 
	// if frame width is greater than output width, we have to trim pixels 
	if(widthbiWidth) 
		hcrop = lpbi->biWidth - width; 
	else 
		hcrop=0; 
 
	// if frame height is greater than output height, we have to trim pixels 
	if(heightbiHeight) 
		vcrop = lpbi->biHeight - height; 
	else 
		vcrop=0; 
 
	if(vertical_size>lpbi->biHeight) 
		topblank = (vertical_size - lpbi->biHeight)/2; 
	else 
		topblank = 0; 
 
	// convert RGB DIB to YUV (4:2:0) 
	lpframeY = (unsigned char *)frame[0]; 
	lpframeU = (unsigned char *)frame[1]; 
	lpframeV = (unsigned char *)frame[2]; 
 
	// take care of any blank lines on the top 
	j = topblank; 
	while(j > 0) 
	{ 
		for(x = 0; x < width; x++) 
		{ 
			*lpframeY++ = 0; 
			Ubuffer[x + (j - 1)*width] = 128; 
			Vbuffer[x + (j - 1)*width] = 128; 
		} 
	j--; 
	} 
	for(y = 0; y < (lpbi->biHeight-(int)vcrop); y++) 
	{ 
		// take care of any blank pixels on the left 
		j = hblank/2; 
		while(j > 0) 
		{ 
			*lpframeY = 0; 
			lpframeY++; 
			Ubuffer[j - 1 + (topblank+y)*width] = 128; 
			Vbuffer[j - 1 + (topblank+y)*width] = 128; 
			j--; 
		} 
		for(x = 0; x < (lpbi->biWidth-(int)hcrop); x++) 
		{ 
			switch(pixsz) 
			{ 
			case 8: 
				lpcurpix = (unsigned char *)(lpbitmp + ((lpbi->biHeight - 1 - (y+(vcrop/2))) * bpscanl) + (x+(hcrop/2))); 
				R = (float)lpColor[*lpcurpix * 4 + 2]; 
				G = (float)lpColor[*lpcurpix * 4 + 1]; 
				B = (float)lpColor[*lpcurpix * 4 + 0]; 
				break; 
			case 16: 
				lpcurpixw = (unsigned short *)(lpbitmp + ((lpbi->biHeight - 1 - (y+(vcrop/2))) * bpscanl) + ((x+(hcrop/2)) * 2)); 
				R = (float)(((*lpcurpixw >> 7) & 0xf8)|0x07); 
				G = (float)(((*lpcurpixw >> 2) & 0xf8)|0x07); 
				B = (float)(((*lpcurpixw << 3) & 0xf8)|0x07); 
				break; 
			case 24: 
				lpcurpix = (unsigned char *)(lpbitmp + ((lpbi->biHeight - 1 - (y+(vcrop/2))) * bpscanl) + ((x+(hcrop/2)) * 3)); 
				R = *(lpcurpix + 2); 
				G = *(lpcurpix + 1); 
				B = *(lpcurpix + 0); 
				break; 
			case 32: 
				lpcurpix = (unsigned char *)(lpbitmp + ((lpbi->biHeight - 1 - (y+(vcrop/2))) * bpscanl) + ((x+(hcrop/2)) * 4)); 
				R = *(lpcurpix + 2); 
				G = *(lpcurpix + 1); 
				B = *(lpcurpix + 0); 
				break; 
			default: 
				fprintf(stderr, "\ninternal error: illegal pixsz value\n"); 
				exit(-1); // should never occur 
			} 
 
			*lpframeY++ = (int)(RY*R + GY*G + BY*B); 
			Ubuffer[(hblank/2)+x + (topblank+y)*width] = (int)(RU*R + GU*G + BU*B + 128); 
			Vbuffer[(hblank/2)+x + (topblank+y)*width] = (int)(RV*R + GV*G + BV*B + 128); 
		} 
		// take care of any blank pixels on the right 
		j = hblank - (hblank/2); 
		while(j > 0) 
		{ 
			*lpframeY = 0; 
			lpframeY++; 
			Ubuffer[lpbi->biWidth + (hblank/2) + j - 1 + (topblank+y)*width] = 128; 
			Vbuffer[lpbi->biWidth + (hblank/2) + j - 1 + (topblank+y)*width] = 128; 
			j--; 
		} 
	} 
	// and any blank lines on the bottom 
	j = vblank - topblank; 
	//printf("j=%u, vblank=%u, vertical_size=%u, biHeight=%u\n",j,vblank,vertical_size,lpbi->biHeight); 
	while(j > 0) 
	{ 
		for(x = 0; x < width; x++) 
		{ 
			*lpframeY++ = 0; 
			Ubuffer[x + (topblank+lpbi->biHeight + j - 1)*width] = 128; 
			Vbuffer[x + (topblank+lpbi->biHeight + j - 1)*width] = 128; 
		} 
	j--; 
	} 
 
	// now do chroma subsampling 
	for(y = 0; y < height/2; y++) 
	{ 
		for(x = 0; x < width/2; x++) 
		{ 
			*lpframeU++ = (Ubuffer[x*2 + (y*2)*width]+Ubuffer[x*2+1 + (y*2)*width]+Ubuffer[x*2 + (y*2+1)*width]+Ubuffer[x*2+1 + (y*2+1)*width])/4; 
			*lpframeV++ = (Vbuffer[x*2 + (y*2)*width]+Vbuffer[x*2+1 + (y*2)*width]+Vbuffer[x*2 + (y*2+1)*width]+Vbuffer[x*2+1 + (y*2+1)*width])/4; 
		} 
	} 
}