📄 stitcher.c
字号:
/** Copyright 2007 Simon Morlat, all rights reserved **/#include <mediastreamer2/msfilter.h>#include <mediastreamer2/msvideo.h>#include <mediastreamer2/msticker.h>#ifdef HAVE_LIBAVCODEC_AVCODEC_H#include <libswscale/swscale.h>#else#include <ffmpeg/swscale.h>#ifdef _MSC_VER /* missing on windows? */#include <ffmpeg/avutil.h>#endif#endif#define STITCHER_MAX_INPUTS 4#define STITCHER_INPUT_TIMEOUT 5000#define AMD_MODE#include "stitcher.h"extern Layout msstitcher_default_layout[];typedef struct _InputInfo{ uint64_t last_frame_time; struct SwsContext *sws_ctx; bool_t active; int counter;} InputInfo;static void input_info_reset_sws(InputInfo *info){ if (info->sws_ctx!=NULL){ sws_freeContext(info->sws_ctx); info->sws_ctx=NULL; }}static void input_info_update(InputInfo *info, uint64_t curtime, bool_t has_data){ if (has_data){ info->active=TRUE; info->last_frame_time=curtime; }else if (curtime-info->last_frame_time>STITCHER_INPUT_TIMEOUT){ input_info_reset_sws(info); info->active=FALSE; }}static void input_info_process(InputInfo *info, mblk_t *im, YuvBuf *dstframe, Region *pos){ YuvBuf inbuf,dest; int x,y,w,h; //AMD float ratio; if (yuv_buf_init_from_mblk(&inbuf,im)!=0) return; w=(float)dstframe->w*pos->w; x=((float)dstframe->w*pos->x)-((float)w/2); //AMDratio=(float)w/(float)inbuf.w; //AMDh=(float)inbuf.h*ratio; //AMD y=((float)dstframe->h*pos->y)-((float)h/2); h=(float)dstframe->h*pos->w; y=((float)dstframe->h*pos->y)-((float)h/2); dest.w=w; dest.h=h; dest.planes[0]=dstframe->planes[0]+(y*dstframe->strides[0])+x; dest.planes[1]=dstframe->planes[1]+((y/2)*dstframe->strides[1])+(x/2); dest.planes[2]=dstframe->planes[2]+((y/2)*dstframe->strides[2])+(x/2); if (info->sws_ctx==NULL){ info->sws_ctx=sws_getContext(inbuf.w,inbuf.h,PIX_FMT_YUV420P, dest.w,dest.h,PIX_FMT_YUV420P,SWS_FAST_BILINEAR, NULL, NULL, NULL); } if (sws_scale(info->sws_ctx,inbuf.planes,inbuf.strides, 0, 0, dest.planes, dstframe->strides)!=0){ ms_error("Error in sws_scale()."); }}typedef struct _StitcherData{ Layout *layout_table; Region *regions; InputInfo inputinfo[STITCHER_MAX_INPUTS]; int counter; int nregions; MSVideoSize vsize; mblk_t *frame_msg; YuvBuf frame;#ifdef AMD_MODE mblk_t *frame_msg_amd_mode; YuvBuf frame_amd_mode;#endif int pin_controller;}StitcherData;static void stitcher_init(MSFilter *f){ StitcherData *s=ms_new0(StitcherData,1); s->vsize.width=MS_VIDEO_SIZE_CIF_W; s->vsize.height=MS_VIDEO_SIZE_CIF_H; s->layout_table=msstitcher_default_layout; f->data=s;}static void stitcher_reset_all(MSFilter *f, StitcherData *d){ int i; for (i=0;i<f->desc->ninputs;++i){ input_info_reset_sws(&d->inputinfo[i]); /* ms_message("nb of incoming image on pin %i: %i", i, d->inputinfo[i].counter); */ d->inputinfo[i].counter=0; } d->pin_controller=0; ms_message("nb of outgoing images %i", d->counter); d->counter=0; /* put frame black */ if (d->frame_msg!=NULL){ int ysize=d->frame.strides[0]*d->frame.h; memset(d->frame.planes[0],16,ysize); memset(d->frame.planes[1],128,ysize/4); memset(d->frame.planes[2],128,ysize/4); }#ifdef AMD_MODE /* put frame black */ if (d->frame_msg_amd_mode!=NULL){ int ysize=d->frame_amd_mode.strides[0]*d->frame_amd_mode.h; memset(d->frame_amd_mode.planes[0],16,ysize); memset(d->frame_amd_mode.planes[1],128,ysize/4); memset(d->frame_amd_mode.planes[2],128,ysize/4); }#endif}static void stitcher_uninit(MSFilter *f){ StitcherData *d=(StitcherData*)f->data; stitcher_reset_all(f,d); ms_free(f->data);}static int check_inputs(MSFilter *f, StitcherData *d){ int i; int active=0; uint64_t curtime=f->ticker->time; for (i=0;i<f->desc->ninputs;++i){ if (f->inputs[i]!=NULL){ input_info_update(&d->inputinfo[i], curtime, !ms_queue_empty(f->inputs[i])); if (d->inputinfo[i].active) ++active; } } return active;}static void stitcher_update_layout(StitcherData *d, int nregions){ Layout *it; for(it=d->layout_table;it->regions!=NULL;++it){ if (it->nregions==nregions){ /*found a layout for this number of regions*/ d->nregions=nregions; d->regions=it->regions; return; } } ms_error("No layout defined for %i regions",nregions);}static void stitcher_preprocess(MSFilter *f){ StitcherData *d=(StitcherData*)f->data; d->frame_msg=yuv_buf_alloc(&d->frame,d->vsize.width,d->vsize.height);#ifdef AMD_MODE d->frame_msg_amd_mode=yuv_buf_alloc(&d->frame_amd_mode,d->vsize.width,d->vsize.height); #endif}static void stitcher_process(MSFilter *f){#ifdef AMD_MODE int update_pin0=-1; int update_pin1=-1;#endif int i,found; mblk_t *im; StitcherData *d=(StitcherData*)f->data; int nregions=check_inputs(f,d); if (d->nregions!=nregions){ stitcher_update_layout(d,nregions); stitcher_reset_all(f,d); d->pin_controller=0; }#ifdef AMD_MODE if (d->nregions==2) { /* special mode to enable video conference with 1 guy: DO NOT send him his own picture. */ /* First INPUT has local SOURCE connected */ if (f->inputs[0]!=NULL && (im=ms_queue_peek_last(f->inputs[0]))!=NULL ){ Region *pos=&msstitcher_default_layout->regions[0]; input_info_process(&d->inputinfo[0],im,&d->frame,pos); ms_queue_flush(f->inputs[0]); //ms_message("WINDS: new image on pin0"); update_pin0=1; } /* second INPUT is some RTP connected */ for (i=1,found=0;i<f->desc->ninputs;++i){ if (f->inputs[i]!=NULL && (im=ms_queue_peek_last(f->inputs[i]))!=NULL ){ Region *pos=&msstitcher_default_layout->regions[0]; input_info_process(&d->inputinfo[i],im,&d->frame_amd_mode,pos); ms_queue_flush(f->inputs[i]); update_pin1=1; break; /* only one in this case */ } } } else { int max=0; update_pin0=1; update_pin1=1; /* select the fastest pin */ d->pin_controller=0; for (i=0,found=0;i<f->desc->ninputs;++i){ if (f->inputs[i]!=NULL && (im=ms_queue_peek_last(f->inputs[i]))!=NULL ){ Region *pos=&d->regions[found]; input_info_process(&d->inputinfo[i],im,&d->frame,pos); ms_queue_flush(f->inputs[i]); d->inputinfo[i].counter++; } if (d->inputinfo[i].counter>max){ max=d->inputinfo[i].counter; d->pin_controller=i; } if (f->inputs[i]!=NULL && d->inputinfo[i].active) ++found; } if (max>20) /* reset */ { for (i=0,found=0;i<f->desc->ninputs;++i){ /* ms_message("nb of incoming image on pin %i: %i", i, d->inputinfo[i].counter); */ if (i==d->pin_controller) d->inputinfo[i].counter=3; /* keep this one advanced to avoid changing too often */ else d->inputinfo[i].counter=0; } /* ms_message("nb of outgoing images %i", d->counter); */ d->counter=0; } }#else for (i=0,found=0;i<f->desc->ninputs;++i){ if (f->inputs[i]!=NULL && (im=ms_queue_peek_last(f->inputs[i]))!=NULL ){ Region *pos=&d->regions[found]; input_info_process(&d->inputinfo[i],im,&d->frame,pos); ms_queue_flush(f->inputs[i]); } if (f->inputs[i]!=NULL && d->inputinfo[i].active) ++found; }#endif#ifdef AMD_MODE if (d->nregions==2) { if (update_pin1==1) /* new frame_msg_amd_mode */ { if (f->outputs[0]!=NULL){ ms_queue_put(f->outputs[0],dupb(d->frame_msg_amd_mode)); } } if (update_pin0==1) /* new frame_msg */ { for(i=1;i<f->desc->noutputs;++i){ if (f->outputs[i]!=NULL){ ms_queue_put(f->outputs[i],dupb(d->frame_msg)); } } } } else { if (d->inputinfo[d->pin_controller].last_frame_time==f->ticker->time) /* the pin controller was updated */ { d->counter++; for(i=0;i<f->desc->noutputs;++i){ if (f->outputs[i]!=NULL){ ms_queue_put(f->outputs[i],dupb(d->frame_msg)); } } } }#else for(i=0;i<f->desc->noutputs;++i){ if (f->outputs[i]!=NULL){ ms_queue_put(f->outputs[i],dupb(d->frame_msg)); } }#endif}static void stitcher_postprocess(MSFilter *f){ StitcherData *d=(StitcherData*)f->data; stitcher_reset_all(f,d); freemsg(d->frame_msg); d->frame_msg=NULL;#ifdef AMD_MODE freemsg(d->frame_msg_amd_mode); d->frame_msg_amd_mode=NULL;#endif}static int stitcher_set_vsize(MSFilter *f, void *data){ StitcherData *d=(StitcherData*)f->data; MSVideoSize *sz=(MSVideoSize*)data; d->vsize=*sz; return 0;}static MSFilterMethod methods[]={ {MS_FILTER_SET_VIDEO_SIZE, stitcher_set_vsize}, {0,NULL}};#ifdef _MSC_VERMSFilterDesc ms_video_stitcher_desc={ MS_FILTER_PLUGIN_ID, "MSVideoStitcher", "A video stitching (mixing) filter", MS_FILTER_OTHER, NULL, STITCHER_MAX_INPUTS, STITCHER_MAX_INPUTS, stitcher_init, stitcher_preprocess, stitcher_process, stitcher_postprocess, stitcher_uninit, methods};#elseMSFilterDesc ms_video_stitcher_desc={ MS_FILTER_PLUGIN_ID, "MSVideoStitcher", "A video stitching (mixing) filter", MS_FILTER_OTHER, NULL, STITCHER_MAX_INPUTS, STITCHER_MAX_INPUTS, stitcher_init, stitcher_preprocess, stitcher_process, stitcher_postprocess, stitcher_uninit, methods};#endif#ifdef WIN32#define GLOBAL_LINKAGE __declspec(dllexport)#else#define GLOBAL_LINKAGE#endifGLOBAL_LINKAGE void libmsvideostitcher_init(void){ ms_filter_register(&ms_video_stitcher_desc);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -