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

📄 theora.c

📁 基于osip、eXosip、speex、ffmpeg的VoIP源代码
💻 C
字号:
/*mediastreamer2 library - modular sound and video processing and streamingCopyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.*/#include "mediastreamer2/msfilter.h"#include "mediastreamer2/msticker.h"#include "mediastreamer2/msvideo.h"#include <theora/theora.h>typedef struct EncState{	theora_state tstate;	theora_info tinfo;	yuv_buffer yuv;	mblk_t *packed_conf;	uint64_t start_time;	uint64_t conf_time;	unsigned int mtu;} EncState;static void enc_init(MSFilter *f){	EncState *s=(EncState *)ms_new(EncState,1);	theora_info_init(&s->tinfo);	s->tinfo.width=MS_VIDEO_SIZE_CIF_W;	s->tinfo.height=MS_VIDEO_SIZE_CIF_H;	s->tinfo.frame_width=MS_VIDEO_SIZE_CIF_W;	s->tinfo.frame_height=MS_VIDEO_SIZE_CIF_H;	s->tinfo.offset_x=0;	s->tinfo.offset_y=0;	s->tinfo.target_bitrate=500000;	s->tinfo.pixelformat=OC_PF_420;	s->tinfo.fps_numerator=15;	s->tinfo.fps_denominator=1;	s->tinfo.aspect_numerator=1;	s->tinfo.aspect_denominator=1;	s->tinfo.colorspace=OC_CS_UNSPECIFIED;	s->tinfo.dropframes_p=0;	s->tinfo.quick_p=1;	s->tinfo.quality=63;	s->tinfo.keyframe_auto_p=1;	s->tinfo.keyframe_frequency=64;	s->tinfo.keyframe_frequency_force=64;	s->tinfo.keyframe_data_target_bitrate=s->tinfo.target_bitrate*1.2;	s->tinfo.keyframe_auto_threshold=80;	s->tinfo.keyframe_mindistance=8;	s->tinfo.noise_sensitivity=1;	s->packed_conf=NULL;	s->start_time=0;	s->conf_time=0;	s->mtu=ms_get_payload_max_size()-6;	f->data=s;}static void enc_uninit(MSFilter *f){	EncState *s=(EncState*)f->data;	theora_info_clear(&s->tinfo);	ms_free(s);}static int enc_set_vsize(MSFilter *f, void*data){	MSVideoSize *vs=(MSVideoSize*)data;	EncState *s=(EncState*)f->data;	s->tinfo.width=vs->width;	s->tinfo.height=vs->height;	s->tinfo.frame_width=vs->width;	s->tinfo.frame_height=vs->height;	return 0;}static int enc_get_vsize(MSFilter *f, void *data){	EncState *s=(EncState*)f->data;	MSVideoSize *vs=(MSVideoSize*)data;	vs->width=s->tinfo.width;	vs->height=s->tinfo.height;	return 0;}static int enc_add_attr(MSFilter *f, void*data){	/*const char *attr=(const char*)data;	EncState *s=(EncState*)f->data;*/	return 0;}static int enc_set_fps(MSFilter *f, void *data){	float *fps=(float*)data;	EncState *s=(EncState*)f->data;	s->tinfo.fps_numerator=*fps;	s->tinfo.keyframe_frequency=(*fps)*5;	s->tinfo.keyframe_frequency_force=(*fps)*5;	return 0;}static int enc_get_fps(MSFilter *f, void *data){	EncState *s=(EncState*)f->data;	float *fps=(float*)data;	*fps=s->tinfo.fps_numerator;	return 0;}static int enc_set_br(MSFilter *f, void*data){	int br=*(int*)data;	EncState *s=(EncState*)f->data;	MSVideoSize vsize;	float fps;	float codecbr=(float)br;	vsize.width=s->tinfo.width;	vsize.height=s->tinfo.height;	fps=s->tinfo.fps_numerator;	s->tinfo.target_bitrate=codecbr*0.8;	s->tinfo.keyframe_data_target_bitrate=codecbr;	/*those default settings would need to be affined*/	if (br>=1024000){		vsize.width = MS_VIDEO_SIZE_4CIF_W;		vsize.height = MS_VIDEO_SIZE_4CIF_H;		s->tinfo.quality=32;		fps=15;	}else if (br>=512000){		vsize.width = MS_VIDEO_SIZE_CIF_W;		vsize.height = MS_VIDEO_SIZE_CIF_H;		s->tinfo.quality=32;		fps=15;	}else if (br>=256000){		vsize.width = MS_VIDEO_SIZE_CIF_W;		vsize.height = MS_VIDEO_SIZE_CIF_H;		s->tinfo.quality=5;		fps=12;	}else if(br>=128000){		vsize.width=MS_VIDEO_SIZE_QCIF_W;		vsize.height=MS_VIDEO_SIZE_QCIF_H;		s->tinfo.quality=20;		fps=10;	}else if(br>=64000){		vsize.width=MS_VIDEO_SIZE_QCIF_W;		vsize.height=MS_VIDEO_SIZE_QCIF_H;		s->tinfo.quality=7;		fps=7;	}	enc_set_vsize(f,&vsize);	enc_set_fps(f,&fps);	return 0;}static int enc_set_mtu(MSFilter *f, void*data){	EncState *s=(EncState*)f->data;	s->mtu=*(int*)data;	return 0;}#define THEORA_RAW_DATA	0#define THEORA_PACKED_CONF 1#define THEORA_COMMENT 2#define THEORA_RESERVED 3#define NOT_FRAGMENTED 0#define START_FRAGMENT 1#define CONT_FRAGMENT 2#define END_FRAGMENT 3static inline void payload_header_set(uint8_t *buf, uint32_t ident, uint8_t ft, uint8_t tdt, uint8_t pkts){	uint32_t tmp;	tmp=((ident&0xFFFFFF)<<8) | ((ft&0x3)<<6) | ((tdt&0x3)<<4) | (pkts&0xf);	*((uint32_t*)buf)=htonl(tmp);}static inline uint32_t payload_header_get_ident(uint8_t *buf){	uint32_t *tmp=(uint32_t*)buf;	return (ntohl(*tmp)>>8) & 0xFFFFFF;}static inline uint32_t payload_header_get_tdt(uint8_t *buf){	uint32_t *tmp=(uint32_t*)buf;	return ((ntohl(*tmp))>>4) & 0x3;}static inline uint32_t payload_header_get_ft(uint8_t *buf){	uint32_t *tmp=(uint32_t*)buf;	return ((ntohl(*tmp))>>6) & 0x3;}static inline uint32_t payload_header_get_pkts(uint8_t *buf){	uint32_t *tmp=(uint32_t*)buf;	return ntohl(*tmp) & 0xf;}static int create_packed_conf(EncState *s){	ogg_packet p;	theora_state *tstate=&s->tstate;	mblk_t *h,*t;	if (theora_encode_header(tstate,&p)!=0){		ms_error("theora_encode_header() error.");		return -1;	}	h=allocb(p.bytes,0);	memcpy(h->b_wptr,p.packet,p.bytes);	h->b_wptr+=p.bytes;	if (theora_encode_tables(tstate,&p)!=0){		ms_error("theora_encode_tables error.");		freemsg(h);		return -1;	}	t=allocb(p.bytes,0);	memcpy(t->b_wptr,p.packet,p.bytes);	t->b_wptr+=p.bytes;	h->b_cont=t;	msgpullup(h,-1);	s->packed_conf=h;	return 0;}static void enc_preprocess(MSFilter *f){	EncState *s=(EncState*)f->data;	int err;	if ((err=theora_encode_init(&s->tstate,&s->tinfo))!=0){		ms_error("error in theora_encode_init() : %i !",err);	}	s->yuv.y_width=s->tinfo.width;	s->yuv.y_height=s->tinfo.height;	s->yuv.y_stride=s->tinfo.width;	s->yuv.uv_width=s->tinfo.width/2;	s->yuv.uv_height=s->tinfo.height/2;	s->yuv.uv_stride=s->tinfo.width/2;	create_packed_conf(s);	s->conf_time=0;	s->start_time=f->ticker->time;}static void enc_postprocess(MSFilter *f){	EncState *s=(EncState*)f->data;	theora_clear(&s->tstate);		//If preprocess is called after postprocess,	//then we loose all info...	//theora_info_clear(&s->tinfo);		if (s->packed_conf) {		freemsg(s->packed_conf);		s->packed_conf=NULL;	}}static void enc_fill_yuv(yuv_buffer *yuv, mblk_t *im){	yuv->y=(uint8_t*)im->b_rptr;	yuv->u=(uint8_t*)im->b_rptr+(yuv->y_stride*yuv->y_height);	yuv->v=(uint8_t*)yuv->u+(yuv->uv_stride*yuv->uv_height);}static void packetize_and_send(MSFilter *f, EncState *s, mblk_t *om, uint32_t timestamp, uint8_t tdt){	mblk_t *packet;	mblk_t *h;	int npackets=0;	static const int ident=0xdede;	while(om!=NULL){		if (om->b_wptr-om->b_rptr>=s->mtu){			packet=dupb(om);			packet->b_wptr=packet->b_rptr+s->mtu;			om->b_rptr=packet->b_wptr;		}else {			packet=om;			om=NULL;		}		++npackets;		h=allocb(6,0);		if (npackets==1){			if (om==NULL)				payload_header_set(h->b_wptr,ident,NOT_FRAGMENTED,tdt,1);			else				payload_header_set(h->b_wptr,ident,START_FRAGMENT,tdt,1);		}else{			if (om==NULL)				payload_header_set(h->b_wptr,ident,END_FRAGMENT,tdt,1);			else				payload_header_set(h->b_wptr,ident,CONT_FRAGMENT,tdt,1);		}		h->b_wptr+=4;		*((uint16_t*)h->b_wptr)=htons(msgdsize(packet));		h->b_wptr+=2;		h->b_cont=packet;		mblk_set_timestamp_info(h,timestamp);		ms_debug("sending theora frame of size %i",msgdsize(h));		ms_queue_put(f->outputs[0],h);	}}bool_t need_send_conf(EncState *s, uint64_t elapsed){#ifdef AMD_HACK	if (elapsed<5000 && elapsed>=s->conf_time){		s->conf_time+=500;		return TRUE;	}#else	/*send immediately then 10 seconds later */	if ( (elapsed<1000 && s->conf_time==0)		|| (elapsed>10000 && s->conf_time==1)){		s->conf_time++;		return TRUE;	}#endif	return FALSE;}static void enc_process(MSFilter *f){	mblk_t *im,*om;	ogg_packet op;	EncState *s=(EncState*)f->data;	uint64_t timems=f->ticker->time;	uint32_t timestamp=timems*90;	uint64_t elapsed=timems-s->start_time;	while((im=ms_queue_get(f->inputs[0]))!=NULL){		/*for the firsts frames only send theora packed conf*/		om=NULL;		if (need_send_conf(s,elapsed)){			if (s->packed_conf) {				om=dupmsg(s->packed_conf);				ms_message("sending theora packed conf (%i bytes)",msgdsize(om));				packetize_and_send(f,s,om,timestamp,THEORA_PACKED_CONF);			}else {				ms_error("No packed conf to send.");			}		}else{			enc_fill_yuv(&s->yuv,im);			ms_debug("subtmitting yuv frame to theora encoder...");			if (theora_encode_YUVin(&s->tstate,&s->yuv)!=0){				ms_error("theora_encode_YUVin error.");			}else{				if (theora_encode_packetout(&s->tstate,0,&op)==1){					ms_debug("Got theora coded frame");					om=allocb(op.bytes,0);					memcpy(om->b_wptr,op.packet,op.bytes);					om->b_wptr+=op.bytes;					packetize_and_send(f,s,om,timestamp,THEORA_RAW_DATA);				}			}		}		freemsg(im);	}}static MSFilterMethod enc_methods[]={	{	MS_FILTER_SET_VIDEO_SIZE, enc_set_vsize },	{	MS_FILTER_SET_FPS,	enc_set_fps	},	{	MS_FILTER_GET_VIDEO_SIZE, enc_get_vsize },	{	MS_FILTER_GET_FPS,	enc_get_fps	},	{	MS_FILTER_ADD_ATTR, enc_add_attr	},	{	MS_FILTER_SET_BITRATE, enc_set_br	},	{	MS_FILTER_SET_MTU, enc_set_mtu	},	{	0			, NULL }};#ifdef _MSC_VERMSFilterDesc ms_theora_enc_desc={	MS_THEORA_ENC_ID,	"MSTheoraEnc",	"The theora video encoder from xiph.org",	MS_FILTER_ENCODER,	"theora",	1,	1,	enc_init,	enc_preprocess,	enc_process,	enc_postprocess,	enc_uninit,	enc_methods};#elseMSFilterDesc ms_theora_enc_desc={	.id=MS_THEORA_ENC_ID,	.name="MSTheoraEnc",	.text="The open-source and royalty-free 'theora' video codec from xiph.org",	.category=MS_FILTER_ENCODER,	.enc_fmt="theora",	.ninputs=1,	.noutputs=1,	.init=enc_init,	.preprocess=enc_preprocess,	.process=enc_process,	.postprocess=enc_postprocess,	.uninit=enc_uninit,	.methods=enc_methods};#endifMS_FILTER_DESC_EXPORT(ms_theora_enc_desc)typedef struct DecState{	theora_state tstate;	theora_info tinfo;	mblk_t *yuv;	mblk_t *curframe;	bool_t ready;}DecState;static void dec_init(MSFilter *f){	DecState *s=(DecState *)ms_new(DecState,1);	s->ready=FALSE;	theora_info_init(&s->tinfo);	s->yuv=NULL;	s->curframe=NULL;	f->data=s;}static void dec_uninit(MSFilter *f){	DecState *s=(DecState*)f->data;	if (s->yuv!=NULL) freemsg(s->yuv);	if (s->curframe!=NULL) freemsg(s->curframe);	theora_info_clear(&s->tinfo);	ms_free(s);}static bool_t dec_init_theora(DecState *s, ogg_packet *op){	theora_comment tcom;	static const int ident_packet_size=42; 	theora_comment_init(&tcom);	tcom.vendor="dummy";	op->b_o_s=1;	if (theora_decode_header(&s->tinfo,&tcom,op)==0){		op->packet+=ident_packet_size;		op->bytes-=ident_packet_size;		/*recall once to decode tables*/		if (theora_decode_header(&s->tinfo,&tcom,op)==0){			if (theora_decode_init(&s->tstate,&s->tinfo)==0){				ms_debug("theora decoder ready, pixfmt=%i",					s->tinfo.pixelformat);				return TRUE;				}		}else{			ms_warning("error decoding theora tables");		}	}else{		ms_warning("error decoding theora header");	}	return FALSE;}/* remove payload header and agregates fragmented packets */static mblk_t *dec_unpacketize(MSFilter *f, DecState *s, mblk_t *im, int *tdt){	uint8_t ft;	*tdt=payload_header_get_tdt((uint8_t*)im->b_rptr);	ft=payload_header_get_ft((uint8_t*)im->b_rptr);	im->b_rptr+=6;		if (ft==NOT_FRAGMENTED)	return im;	if (ft==START_FRAGMENT){		if (s->curframe!=NULL)			freemsg(s->curframe);		s->curframe=im;	}else if (ft==CONT_FRAGMENT){		if (s->curframe!=NULL)			concatb(s->curframe,im);		else			freemsg(im);	}else{/*end fragment*/		if (s->curframe!=NULL){			mblk_t *ret;			concatb(s->curframe,im);			msgpullup(s->curframe,-1);			ret=s->curframe;			s->curframe=NULL;			return ret;		}else			freemsg(im);	}	return NULL;}static void dec_process_frame(MSFilter *f, DecState *s, ogg_packet *op){	yuv_buffer yuv;	if (theora_decode_packetin(&s->tstate,op)==0){		if (theora_decode_YUVout(&s->tstate,&yuv)==0){			mblk_t *om;			int i;			int ylen=yuv.y_width*yuv.y_height;			int uvlen=yuv.uv_width*yuv.uv_height;			ms_debug("Got yuv buffer from theora decoder");			if (s->yuv==NULL){				int len=(ylen)+(2*uvlen);				s->yuv=allocb(len,0);			}			om=dupb(s->yuv);			for(i=0;i<yuv.y_height;++i){				memcpy(om->b_wptr,yuv.y+yuv.y_stride*i,yuv.y_width);				om->b_wptr+=yuv.y_width;			}			for(i=0;i<yuv.uv_height;++i){				memcpy(om->b_wptr,yuv.u+yuv.uv_stride*i,yuv.uv_width);				om->b_wptr+=yuv.uv_width;			}			for(i=0;i<yuv.uv_height;++i){				memcpy(om->b_wptr,yuv.v+yuv.uv_stride*i,yuv.uv_width);				om->b_wptr+=yuv.uv_width;			}			ms_queue_put(f->outputs[0],om);		}	}else{		ms_warning("theora decoding error");	}}static void dec_process(MSFilter *f){	mblk_t *im;	mblk_t *m;	ogg_packet op;	int tdt;	DecState *s=(DecState*)f->data;	while( (im=ms_queue_get(f->inputs[0]))!=0) {		m=dec_unpacketize(f,s,im,&tdt);		if (m!=NULL){			/* now in im we have only the theora data*/			op.packet=(uint8_t*)m->b_rptr;			op.bytes=m->b_wptr-m->b_rptr;			op.b_o_s=0;			op.e_o_s=0;			op.granulepos=0;			op.packetno=0;			if (tdt!=THEORA_RAW_DATA) /*packed conf*/ {				if (!s->ready){					if (dec_init_theora(s,&op))						s->ready=TRUE;				}			}else{				if (s->ready){					dec_process_frame(f,s,&op);				}else{					ms_warning("skipping theora packet because decoder was not initialized yet with theora header and tables");				}			}			freemsg(m);		}	}}#ifdef _MSC_VERMSFilterDesc ms_theora_dec_desc={	MS_THEORA_DEC_ID,	"MSTheoraDec",	"The theora video decoder from xiph.org",	MS_FILTER_DECODER,	"theora",	1,	1,	dec_init,	NULL,	dec_process,	NULL,	dec_uninit,	NULL};#elseMSFilterDesc ms_theora_dec_desc={	.id=MS_THEORA_DEC_ID,	.name="MSTheoraDec",	.text="The theora video decoder from xiph.org",	.category=MS_FILTER_DECODER,	.enc_fmt="theora",	.ninputs=1,	.noutputs=1,	.init=dec_init,	.process=dec_process,	.uninit=dec_uninit};#endifMS_FILTER_DESC_EXPORT(ms_theora_dec_desc)

⌨️ 快捷键说明

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