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

📄 capproc.cc

📁 这个软件的功能同我上次传的那个avifile.也是linux上的一个用于多媒体应用的源码。
💻 CC
字号:
#include "capproc.h"#include "dsp.h"#include <unistd.h>#include <stdio.h>#include <avifile.h>#include <videoencoder.h>#include <iostream>#  include <avm_fourcc.h>#  include <utils.h>#  include <cpuinfo.h>#  include <creators.h>#  include <except.h>using namespace Creators;using namespace std;#define __MODULE__ "Capture Process"/* Class      : frame_allocator * Description: Manages a stack of frames. It gives out pointers to  *            : frames that can be written to. * Parameters : None. * Returns    : Nothing. * SideEffects: None. */class frame_allocator{	struct frame	{		char* data; /* frame number (int, first 4 bytes) + frame data */		int status; /* is this frame available for capturing? */	};	int _w; 	int _h;	vector<frame> frames;	unsigned int _limit;	int refs;public:	frame_allocator(int w, int h, int limit):_w(w), _h(h), _limit(limit),refs(2){}	/* Function   : release	 * Description: No clue. But if you call it three times in a row, it will	 *            : destruct this instance. Before that, it will just decrease	 *            : a reference counter.	 * Parameters : None.	 * Returns    : Nothing.	 * SideEffects: None.	 */	void release()	{		refs--;		if (!refs)		{			delete this;		}	}		/* Function   : alloc	 * Description: Returns a pointer to a memory area to write framedata to.	 * Parameters : None.	 * Returns    : Nothing.	 * SideEffects: None.	 */	char* alloc()	{		unsigned int i;		/* possibly there's an unused frame (status == 0) to store the data in.		 * If so, find it and return a pointer to where the captured data can		 * be stored.		 */		for(i=0; i<frames.size(); i++)		{			if(frames[i].status==0)			{				frames[i].status=1;				*(int*)(frames[i].data)=i;				return frames[i].data+4;			}			}		/* no unused frame found. Create a new one and push it on the frames		 * stack		 */		if(frames.size()>=_limit)return 0;		frame f;		/* 3 == 3 bytes for each pixel. Blerh. 4 == framenumer. Blergh++. */		f.data=new char[_w*_h*3+4];		f.status=1;		frames.push_back(f);		*(int*)(f.data)=i;		return f.data+4;	}	/* Function   : free	 * Description: Marks a frame unused by settings its status flag to 0	 * Parameters : mem	 *            :   Pointer to frame data (+4), as given out by	 *            :   this->alloc() before.	 * Returns    : Nothing.	 * SideEffects: None.	 */	void free(char* mem)	{		if(!mem)		{			/* really should throw an exception here. */			cerr<<"ERROR: Freeing 0!"<<endl;			return;		}		int id=*(int*)(mem-4);		/* is this really a pointer within a valid frame ? */		if((id<0)||((unsigned)id>=frames.size())||(frames[id].data!=(mem-4)))		{			cerr<<"ERROR: Freeing unknown memory!"<<endl;			return;		}		if(frames[id].status==0)		{			/* it wasn't even used. */			cerr<<"ERROR: Duplicate free()!"<<endl;			return;		}		frames[id].status=0;	}	 	~frame_allocator()	{		for(unsigned int i=0; i<frames.size(); i++)			delete frames[i].data;	}};static frame_allocator* _allocator=0;void* CaptureProcess::vidcap(void* arg){	CaptureProcess& a=*(CaptureProcess*)arg;	int w=a.res_w;	int h=a.res_h;	const float fps=a.fps;	debug("Starting video capture thread.");//	  char tmpframe[384*288*4];	a.m_v4l->grabSetParams(1, &w, &h, VIDEO_PALETTE_RGB24);	debug("Set capture parameters.");	long long& inittime=a.starttime;	int& cnt=a.cnt;	int& drop=a.cap_drop;	cnt=0;	drop=0;	/* reserve space for 50 unencoded frames */	_allocator=new frame_allocator(w,h,50);	/* start the capture loop until something makes us quit */	while(!a.m_quit)	{		long long currenttime=longcount();		char* z=0;//		cerr<<currenttime<<" "<<inittime<<" "<<fps<<std::endl;//		cerr<<to_float(currenttime, inittime)*fps<<" "<<cnt<<std::endl;//		double freq=550000.;		/* Are we ready for the next frame yet? */		double dist=double(currenttime-inittime)/(freq*1000.);		if(dist*fps<cnt)		{			/* No, the current frame is still out there.. let's take a short nap. */			avm_usleep(10000);			continue;		}	 		chunk ch;		/* Did we wait too long and are we too late for our new frame? */		if(dist*fps<(cnt+1))		{			/* Nope, we're in time. Capture the mofo. */			z=a.m_v4l->grabCapture(false);			char* tmpframe=_allocator->alloc();						if(tmpframe)			{				// o_* original_*; c_* capture_*				int c_lines = a.window.height;				int c_bpl = a.window.width * 3;								int o_bpl = w * 3;				int o_y_end = a.window.y + a.window.height;				int o_x_off = a.window.x * 3;				char *last_line_buffer = NULL;								if (a.vertical_flip)				{					/* pointer to last line in buffer. Used ofte in line loop */					last_line_buffer = tmpframe + (c_lines - 1) * c_bpl;				}				for (int i = 0; i < c_lines; i++)				{					char *line_buffer;					if (a.vertical_flip)						line_buffer = last_line_buffer - (i * c_bpl);					else						line_buffer = tmpframe + (i * c_bpl);					memcpy(line_buffer, z + (o_y_end -i -1)*o_bpl + o_x_off, c_bpl);				}			}			ch.data=tmpframe;		}		else 		{			ch.data=0;			drop++;		} 		ch.timestamp=dist;		a.m_vidq.push(ch);		cnt++;		//if(cnt%100==0)		//	 cerr<<"Capture thread: read "<<cnt<<" frames, dropped "<<drop<<" frames"<<std::endl;	}	_allocator->release();	cerr<<"Capture thread exiting"<<endl;	return 0;}int audioblock=0;void* CaptureProcess::audcap(void* arg){	CaptureProcess& a=*(CaptureProcess*)arg;	cerr << "Opening dsp...." << endl;	dsp* thedsp=new dsp(a.sound_dev);	cerr << "Dsp opened!" << endl;	if ( thedsp->opendev(a.samplesize,a.chan,a.frequency) ==0 )	{		//returns file descriptor		return 0;	}	cerr << "Dsp configuration set." << endl;	float abps = a.samplesize * a.chan * a.frequency / 8; // #bytes / second	char* buf = NULL;	int bufsize = 0;	int blocksize = thedsp->getBufSize();	int tim = 0;	int counter = 0;	audioblock = blocksize;	while(!a.m_quit)	{		buf = new char[audioblock];		memcpy(buf, thedsp->readBuf(), audioblock);		long long ct = longcount();		double timestamp_shift = (audioblock + thedsp->getSize()) / abps;		if (!(counter%10))			cerr << "Timeshift: " << timestamp_shift << ", getSize(): " <<				thedsp->getSize() << endl;		chunk ch;		ch.data=buf;		if(a.starttime)		{			ch.timestamp = (double(ct - a.starttime) / (freq * 1000.)) - 				timestamp_shift;		}		else		{			ch.timestamp=-1;		}		a.m_audq.push(ch);		bufsize+=blocksize;		tim++;		if ( blocksize / abps > .1 )		{			avm_usleep(10000);		}		counter++;	}	delete thedsp;	return 0;}void* CaptureProcess::writer(void* arg){	CaptureProcess& a=*(CaptureProcess*)arg;	IAviWriteFile* file=0;	IAviSegWriteFile* sfile=0;					debug("Starting writer thread.");	IAviVideoWriteStream* stream;	IAviWriteStream* audioStream=0;	IAviAudioWriteStream *mp3Stream = 0;	BitmapInfo bh(a.window.width, a.window.height, 24);		const double fps=a.fps;	if(fps==0)	{		throw FATAL("FPS = 0 !");	}	try	{		debug("Creating AVI file..");		if(a.segment_size==-1)				file=CreateIAviWriteFile(a.filename.c_str());		else		{				sfile=CreateSegmentedFile(a.filename.c_str(), a.segment_size);				file=sfile;		}				 		//		FILE* zz=fopen("bin/uncompr.bmp", "rb");		debug("Adding video stream.");		stream=file->AddVideoStream(a.compressor, &bh, int(1000000./a.fps));		debug("Done.");		//		stream=file->AddStream(AviStream::Video);		//		ve.Init(fccIV50, (const char*)&bh);	}	catch(FatalError& e)	{		e.Print();		a.m_quit=1;		return 0;	}				 				float abps=(a.samplesize*a.frequency*a.chan)/8;	WAVEFORMATEX wfm;	wfm.wFormatTag=1;//PCM	wfm.nChannels=a.chan;	wfm.nSamplesPerSec=a.frequency;	wfm.nAvgBytesPerSec=(int)abps;	wfm.nBlockAlign=(a.samplesize*a.chan)/8;	wfm.wBitsPerSample=a.samplesize;	wfm.cbSize=0;	if(audioStream==0 && mp3Stream == 0)	{		if (a.audiocodec)		{			debug("Adding mp3 audio stream.");			mp3Stream = file->AddAudioStream(				a.audiocodec,				&wfm,				a.audiobitrate);			mp3Stream->Start();			debug("Done.");		}		else		{			debug("Adding uncompressed audio stream.");			audioStream=file->AddStream(AviStream::Audio,				(const char*)&wfm, 18,				1, //uncompressed PCM data				(int)abps, //bytes/sec				(a.samplesize*a.chan)/8			//bytes/sample			);			debug("Done.");		}	}				//ve.SetQuality(9500);	//ve.Start();	stream->SetQuality(a.quality);	stream->Start();	cerr<<"Entering loop"<<endl;	//BITMAPINFOHEADER obh=ve.QueryOutputFormat();	//stream->SetFormat((const char*)&obh, sizeof obh);	int cnt=0;	int& drop=a.comp_drop;	long long audiodata=0LL;	int videodata=0;	double video_error=0;	int hide_video=0;	int dup_video=0;	int finished = 0;	double snd_time = 0;	double vid_time = 0;	drop=0;		while(!finished)	{		chunk ch;		int finished = 0;		while(a.m_vidq.size()>50) // skip frames if queue is too full		{			ch=a.m_vidq.front();			a.m_vidq.pop();			vid_time=ch.timestamp;			cnt++;			if(ch.data)//delete ch.data;					_allocator->free(ch.data);			stream->AddFrame(0);			videodata++;			drop++;		}		while((a.m_vidq.size()==0) && (a.m_audq.size()==0)) // ok empty		{			if(a.m_quit)			{				finished = 1;				break;			}			avm_usleep(10000);		}				 		if (finished)			break;		if(a.m_vidq.size()) // something to do		{			ch=a.m_vidq.front();			a.m_vidq.pop();			vid_time=ch.timestamp;			cnt++;			if(!hide_video)			{				videodata++;				CImage* im=0;				if(ch.data)					im=new CImage(&bh, (unsigned char*)ch.data, false);				stream->AddFrame(im);				if(dup_video)				{					videodata++;					stream->AddFrame(im);					video_error+=1./fps;				}				if(im)					im->Release();			}			else				video_error-=1./fps;			dup_video=hide_video=0;			if(ch.data)				_allocator->free(ch.data);		}		if(a.m_audq.size())		{			ch=a.m_audq.front();			a.m_audq.pop();			//std::cerr<<ch.timestamp-snd_time<<" "<<ch.timestamp-(audiodata+audioblock)/44100./2<<std::endl;			snd_time=ch.timestamp;			if (a.audiocodec)			{				mp3Stream->AddData(ch.data, audioblock);			}			else			{				audioStream->AddChunk(ch.data, audioblock, AviStream::KEYFRAME);			}			audiodata+=audioblock;			double audio_error=audiodata/abps-ch.timestamp;			if(audio_error<video_error-5./fps)			{				hide_video=1;			}			if(audio_error>video_error+5./fps)			{				dup_video=1;			}			delete ch.data;		}		if(a.segment_flag && sfile)		{				sfile->Segment();				a.segment_flag=0;				//vid_clear=aud_clear=0;		}				if(a.timelimit!=-1)		{		  if(snd_time>a.timelimit)			{			  a.m_quit=1;			}		  if(vid_time>a.timelimit)			{			  a.m_quit=1;			}		}		if(a.sizelimit!=-1)		{			if(file->GetFileSize()>a.sizelimit)			{				a.m_quit=1;			}		}			}	long long size=file->GetFileSize();	delete file;	_allocator->release();	cerr<<"Write thread exiting"<<endl;	(*a.messenger)<<"Audio: written "<<(long int)audiodata<<" bytes ( "<<(long int)(audiodata/(44100.*2))<<" s )."<<endl;	(*a.messenger)<<"Video: written "<<videodata<<" frames ( "<<videodata/fps<<" s )."<<endl;	(*a.messenger)<<"End video pos "<<vid_time<<" s, end audio pos "<<snd_time<<" s."<<endl;	(*a.messenger)<<"File size: "<<(double)(size/1000)<<" Kb ( "<<(double)(size/1000/vid_time)<<" Kb/s )."<<endl;	(*a.messenger)<<"Synch fix: "<<videodata-cnt<<" frames."<<endl;	(*a.messenger)<<"Frame drop: "<<100.*double(a.cap_drop+drop)/videodata<<"%."<<endl<<flush;	(*a.messenger)<<ends;	return 0;}void CaptureProcess::Create(v4lxif* v4l,	string filename,	int segment_size,				int compressor,					int quality,					int keyframes,					enum Sound_Freqs frequency,		enum Sample_Sizes samplesize,	enum Sound_Chans chan,	enum Resolutions res,	int timelimit,					int sizelimit,	float fps,	window_t window,	int audiocodec,	int audiobitrate,	int vertical_flip,	const char *sound_dev){ 	m_v4l=v4l;	m_quit=0;	this->cap_drop = 0;	starttime=longcount();	this->filename=filename;	this->segment_size=segment_size;	this->compressor=compressor;	this->quality=quality;	this->keyframes=keyframes;	this->audiocodec = audiocodec;	this->audiobitrate = audiobitrate;	this->vertical_flip = vertical_flip;	this->sound_dev = sound_dev;	//TODO: debug stream	cerr << "Audiocodec: " << audiocodec << ", bitrate: " << audiobitrate		<< endl;	switch(frequency)	{		case NoAudio:			break;		case F44:			this->frequency=44100;			break;		case F22:			this->frequency=22050;			break;		case F11:			this->frequency=11025;			break;		default:			throw FATAL("Unknown frequency");	}		if(frequency!=NoAudio)	{		switch(samplesize)		{			case S16:				this->samplesize=16;				break;			case S8:				this->samplesize=8;				break;			default:				throw FATAL("Unknown audio sample size");		}		switch(chan)		{			case Mono:				this->chan=1;				break;			case Stereo:				this->chan=2;				break;			default:				throw FATAL("Unknown channel number");		}  	}  	int i = 0;	while (restable[i].res != res && restable[i].res != WNONE)	{		i++;	}	if (restable[i].res == res)	{		res_w = restable[i].width;		res_h = restable[i].height;	}	else	{		throw FATAL("Unknown video resolution");	}		this->timelimit=timelimit;	this->sizelimit=sizelimit;	this->fps=fps;	this->window = window;	printf ("window: %i %i %i %i \n", window.x, window.width, window.y, window.height);	pthread_create(&m_vidc, 0, CaptureProcess::vidcap, this);	if(frequency!=NoAudio)	{		pthread_create(&m_audc, 0, CaptureProcess::audcap, this);	}	pthread_create(&m_writer, 0, CaptureProcess::writer, this);}CaptureProcess::~CaptureProcess(){	m_quit=1;	cerr << "Waiting for write thread" << endl;;	pthread_join(m_writer,0);	cerr << "Waiting for audio thread" << endl;;	pthread_join(m_audc,0);	cerr << "Waiting for video thread" << endl;;	pthread_join(m_vidc,0);	cerr<<"All threads exited"<<endl;	while(m_audq.size())	{		chunk z=m_audq.front();		m_audq.pop();		if(z.data)delete z.data;	}	}// vim:ts=2:sw=2

⌨️ 快捷键说明

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