mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-02-04 04:09:19 +00:00
new winvideo2 is working well.
git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@108 3f6dc0c8-ddfe-455d-9043-3cd528dc4637
This commit is contained in:
parent
11d7f45abd
commit
b4c1f8610e
3 changed files with 466 additions and 1 deletions
|
|
@ -1,5 +1,8 @@
|
|||
|
||||
EXTRA_DIST= winsnd2.c winsnd.c winvideo.c winvideods.c wincevideods.c dxfilter.h dxfilter.cpp msfileplayer_win.c msfilerec_win.c winsndds.cpp nowebcamCIF.jpg winsnd3.c vfw-missing.h
|
||||
EXTRA_DIST= winsnd2.c winsnd.c winvideo.c \
|
||||
winvideods.c wincevideods.c dxfilter.h dxfilter.cpp \
|
||||
msfileplayer_win.c msfilerec_win.c winsndds.cpp nowebcamCIF.jpg winsnd3.c vfw-missing.h \
|
||||
winvideo2.c
|
||||
|
||||
BUILT_SOURCES=alldescs.h
|
||||
|
||||
|
|
|
|||
|
|
@ -136,6 +136,10 @@ static void pixconv_process(MSFilter *f){
|
|||
s->out_fmt,SWS_FAST_BILINEAR,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
if (s->in_fmt==PIX_FMT_BGR24){
|
||||
inbuf.data[0]+=inbuf.linesize[0]*(s->size.height-1);
|
||||
inbuf.linesize[0]=-inbuf.linesize[0];
|
||||
}
|
||||
if (sws_scale(s->sws_ctx,inbuf.data,inbuf.linesize, 0,
|
||||
s->size.height, s->outbuf.planes, s->outbuf.strides)<0){
|
||||
ms_error("MSPixConv: Error in sws_scale().");
|
||||
|
|
|
|||
458
linphone/mediastreamer2/src/winvideo2.c
Executable file
458
linphone/mediastreamer2/src/winvideo2.c
Executable file
|
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
mediastreamer2 library - modular sound and video processing and streaming
|
||||
Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
|
||||
|
||||
This program 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
|
||||
of 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 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "mediastreamer2/msvideo.h"
|
||||
#include "mediastreamer2/msticker.h"
|
||||
#include "mediastreamer2/msv4l.h"
|
||||
#include "Vfw.h"
|
||||
#include <winuser.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#include "mediastreamer2/mswebcam.h"
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include "vfw-missing.h"
|
||||
#endif
|
||||
|
||||
typedef void (*queue_msg_t)(void *, mblk_t *);
|
||||
|
||||
typedef struct VfwEngine{
|
||||
ms_thread_t thread;
|
||||
char dev[512];
|
||||
int devidx;
|
||||
HWND capvideo;
|
||||
MSVideoSize vsize;
|
||||
MSPixFmt pix_fmt;
|
||||
queue_msg_t cb;
|
||||
void *cb_data;
|
||||
bool_t started;
|
||||
bool_t thread_running;
|
||||
}VfwEngine;
|
||||
|
||||
#define VFW_ENGINE_MAX_INSTANCES 9
|
||||
|
||||
static VfwEngine *engines[VFW_ENGINE_MAX_INSTANCES]={0};
|
||||
|
||||
static bool_t try_format(VfwEngine *s, BITMAPINFO *videoformat, MSPixFmt pixfmt){
|
||||
bool_t ret;
|
||||
capGetVideoFormat(s->capvideo, videoformat, sizeof(BITMAPINFO));
|
||||
videoformat->bmiHeader.biSizeImage = 0;
|
||||
videoformat->bmiHeader.biWidth = s->vsize.width;
|
||||
videoformat->bmiHeader.biHeight = s->vsize.height;
|
||||
switch(pixfmt){
|
||||
case MS_YUV420P:
|
||||
videoformat->bmiHeader.biBitCount = 12;
|
||||
videoformat->bmiHeader.biCompression=MAKEFOURCC('I','4','2','0');
|
||||
break;
|
||||
case MS_YUY2:
|
||||
videoformat->bmiHeader.biBitCount = 16;
|
||||
videoformat->bmiHeader.biCompression=MAKEFOURCC('Y','U','Y','2');
|
||||
break;
|
||||
case MS_RGB24:
|
||||
videoformat->bmiHeader.biBitCount = 24;
|
||||
videoformat->bmiHeader.biCompression=BI_RGB;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
ret=capSetVideoFormat(s->capvideo, videoformat, sizeof(BITMAPINFO));
|
||||
if (ret) {
|
||||
/*recheck video format */
|
||||
capGetVideoFormat(s->capvideo, videoformat, sizeof(BITMAPINFO));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _vfw_engine_select_format(VfwEngine *obj){
|
||||
BITMAPINFO videoformat;
|
||||
MSPixFmt driver_last;
|
||||
char compname[5];
|
||||
|
||||
capGetVideoFormat(obj->capvideo, &videoformat, sizeof(BITMAPINFO));
|
||||
memcpy(compname,&videoformat.bmiHeader.biCompression,4);
|
||||
ms_message("vfw: camera's current format is %s", compname);
|
||||
driver_last=ms_fourcc_to_pix_fmt(videoformat.bmiHeader.biCompression);
|
||||
if (driver_last!=MS_PIX_FMT_UNKNOWN && try_format(obj,&videoformat,driver_last)){
|
||||
ms_message("Using driver last setting");
|
||||
obj->pix_fmt=driver_last;
|
||||
}else if (try_format(obj,&videoformat,MS_YUV420P)){
|
||||
obj->pix_fmt=MS_YUV420P;
|
||||
ms_message("Using YUV420P");
|
||||
}else if (try_format(obj,&videoformat,MS_RGB24)){
|
||||
obj->pix_fmt=MS_RGB24;
|
||||
ms_message("Using RGB24");
|
||||
}else if (try_format(obj,&videoformat,MS_YUY2)){
|
||||
obj->pix_fmt=MS_YUY2;
|
||||
ms_message("Using YUY2");
|
||||
}else{
|
||||
ms_error("v4w: Failed to set any video format.");
|
||||
return -1;
|
||||
}
|
||||
if (obj->pix_fmt==MS_RGB24){
|
||||
if (videoformat.bmiHeader.biHeight>0){
|
||||
obj->pix_fmt=MS_RGB24_REV;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dummy(void*p){
|
||||
}
|
||||
|
||||
LRESULT CALLBACK vfw_engine_stream_callback(HWND hWnd, LPVIDEOHDR lpVHdr)
|
||||
{
|
||||
VfwEngine *s;
|
||||
mblk_t *buf;
|
||||
int size;
|
||||
|
||||
s = (VfwEngine *)capGetUserData(hWnd);
|
||||
if (s==NULL)
|
||||
return FALSE;
|
||||
|
||||
size = lpVHdr->dwBufferLength;
|
||||
if (size>0 && s->cb!=NULL && s->started){
|
||||
buf = esballoc(lpVHdr->lpData,size,0,dummy);
|
||||
buf->b_wptr+=size;
|
||||
s->cb(s->cb_data,buf);
|
||||
}
|
||||
return TRUE ;
|
||||
}
|
||||
|
||||
static void *
|
||||
vfw_engine_thread(void *arg)
|
||||
{
|
||||
VfwEngine *s=(VfwEngine*)arg;
|
||||
MSG msg;
|
||||
|
||||
while(s->thread_running)
|
||||
{
|
||||
BOOL fGotMessage;
|
||||
if((fGotMessage = PeekMessage(&msg, (HWND) s->capvideo, 0, 0, PM_REMOVE)) != 0)
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
else
|
||||
Sleep(10);
|
||||
}
|
||||
ms_thread_exit(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void vfw_engine_destroy(VfwEngine *obj){
|
||||
if (!capCaptureStop(obj->capvideo)){
|
||||
ms_error("vfw: fail to stop capture !");
|
||||
}
|
||||
obj->thread_running=FALSE;
|
||||
ms_thread_join(obj->thread,NULL);
|
||||
capDriverDisconnect(obj->capvideo);
|
||||
DestroyWindow(obj->capvideo);
|
||||
}
|
||||
|
||||
static int _vfw_engine_setup(VfwEngine *obj){
|
||||
CAPTUREPARMS capparam ;
|
||||
capCaptureGetSetup(obj->capvideo,&capparam,sizeof(capparam)) ;
|
||||
capparam.dwRequestMicroSecPerFrame = 100000 ;
|
||||
// detach capture from application
|
||||
capparam.fYield = TRUE ;
|
||||
capparam.fMakeUserHitOKToCapture = FALSE;
|
||||
capparam.fAbortLeftMouse = FALSE;
|
||||
capparam.fAbortRightMouse = FALSE;
|
||||
capparam.wPercentDropForError = 90 ;
|
||||
capparam.fCaptureAudio = FALSE ;
|
||||
capparam.fAbortRightMouse = FALSE;
|
||||
capparam.fAbortLeftMouse = FALSE;
|
||||
capparam.AVStreamMaster = AVSTREAMMASTER_NONE ;
|
||||
if (!capCaptureSetSetup(obj->capvideo,&capparam,sizeof(capparam))){
|
||||
ms_error("capCaptureSetSetup failed.");
|
||||
return -1;
|
||||
}
|
||||
capSetUserData(obj->capvideo, obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VfwEngine * vfw_engine_new(int i){
|
||||
char dev[512];
|
||||
char ver[512];
|
||||
VfwEngine *obj=ms_new0(VfwEngine,1);
|
||||
if (capGetDriverDescription(i, dev, sizeof (dev),
|
||||
ver, sizeof (ver))){
|
||||
MSVideoSize sz=MS_VIDEO_SIZE_CIF;
|
||||
HWND hwnd=capCreateCaptureWindow("Capture Window",WS_CHILD /* WS_OVERLAPPED */
|
||||
,0,0,sz.width,sz.height,HWND_MESSAGE, 0) ;
|
||||
|
||||
if (hwnd==NULL) return NULL;
|
||||
if(!capDriverConnect(hwnd,i)){
|
||||
ms_warning("vfw: could not connect to capture driver, no webcam connected.");
|
||||
DestroyWindow(hwnd);
|
||||
return NULL;
|
||||
}
|
||||
strcpy(obj->dev,dev);
|
||||
obj->devidx=i;
|
||||
obj->capvideo=hwnd;
|
||||
obj->vsize=sz;
|
||||
|
||||
if (_vfw_engine_setup(obj)==-1){
|
||||
vfw_engine_destroy(obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_vfw_engine_select_format(obj)==-1){
|
||||
vfw_engine_destroy(obj);
|
||||
return NULL;
|
||||
}
|
||||
capSetCallbackOnVideoStream(obj->capvideo, vfw_engine_stream_callback);
|
||||
if (!capCaptureSequenceNoFile(obj->capvideo)){
|
||||
ms_error("vfw: fail to start capture !");
|
||||
}
|
||||
ms_thread_create(&obj->thread,NULL,vfw_engine_thread,obj);
|
||||
engines[i]=obj;
|
||||
return obj;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static MSPixFmt vfw_engine_get_pix_fmt(VfwEngine *obj){
|
||||
return obj->pix_fmt;
|
||||
}
|
||||
|
||||
static MSVideoSize vfw_engine_get_video_size(VfwEngine *obj){
|
||||
return obj->vsize;
|
||||
}
|
||||
|
||||
static void vfw_engine_set_callback(VfwEngine* obj, queue_msg_t cb, void *cb_data){
|
||||
obj->cb=cb;
|
||||
obj->cb_data=cb_data;
|
||||
}
|
||||
|
||||
static void vfw_engine_start_capture(VfwEngine *obj){
|
||||
obj->started=TRUE;
|
||||
}
|
||||
|
||||
static void vfw_engine_stop_capture(VfwEngine *obj){
|
||||
obj->started=FALSE;
|
||||
}
|
||||
|
||||
static void vfw_engines_free(void){
|
||||
int i;
|
||||
for(i=0;i<VFW_ENGINE_MAX_INSTANCES;++i){
|
||||
if (engines[i])
|
||||
vfw_engine_destroy(engines[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct VfwState{
|
||||
MSVideoSize vsize;
|
||||
queue_t rq;
|
||||
ms_mutex_t mutex;
|
||||
int frame_ind;
|
||||
int frame_max;
|
||||
float fps;
|
||||
float start_time;
|
||||
int frame_count;
|
||||
VfwEngine *eng;
|
||||
} VfwState;
|
||||
|
||||
|
||||
static void vfw_init(MSFilter *f){
|
||||
VfwState *s=(VfwState *)ms_new0(VfwState,1);
|
||||
s->vsize.width=MS_VIDEO_SIZE_CIF_W;
|
||||
s->vsize.height=MS_VIDEO_SIZE_CIF_H;
|
||||
qinit(&s->rq);
|
||||
ms_mutex_init(&s->mutex,NULL);
|
||||
s->start_time=0;
|
||||
s->frame_count=-1;
|
||||
s->fps=15;
|
||||
f->data=s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void vfw_uninit(MSFilter *f){
|
||||
VfwState *s=(VfwState*)f->data;
|
||||
flushq(&s->rq,0);
|
||||
ms_mutex_destroy(&s->mutex);
|
||||
ms_free(s);
|
||||
}
|
||||
|
||||
static void vfw_callback(void *data, mblk_t *m){
|
||||
VfwState *s=(VfwState*)data;
|
||||
ms_mutex_lock(&s->mutex);
|
||||
putq(&s->rq,m);
|
||||
ms_mutex_unlock(&s->mutex);
|
||||
}
|
||||
|
||||
static void vfw_preprocess(MSFilter * obj){
|
||||
VfwState *s=(VfwState*)obj->data;
|
||||
if (s->eng==NULL) s->eng=engines[0];
|
||||
vfw_engine_set_callback(s->eng,vfw_callback,s);
|
||||
vfw_engine_start_capture(s->eng);
|
||||
}
|
||||
|
||||
static void vfw_postprocess(MSFilter * obj){
|
||||
VfwState *s=(VfwState*)obj->data;
|
||||
vfw_engine_stop_capture(s->eng);
|
||||
flushq(&s->rq,0);
|
||||
}
|
||||
|
||||
static void vfw_process(MSFilter * obj){
|
||||
VfwState *s=(VfwState*)obj->data;
|
||||
mblk_t *m;
|
||||
uint32_t timestamp;
|
||||
int cur_frame;
|
||||
|
||||
if (s->frame_count==-1){
|
||||
s->start_time=obj->ticker->time;
|
||||
s->frame_count=0;
|
||||
}
|
||||
|
||||
|
||||
cur_frame=((obj->ticker->time-s->start_time)*s->fps/1000.0);
|
||||
if (cur_frame>s->frame_count){
|
||||
mblk_t *om=NULL;
|
||||
/*keep the most recent frame if several frames have been captured */
|
||||
if (s->eng!=NULL){
|
||||
ms_mutex_lock(&s->mutex);
|
||||
while((m=getq(&s->rq))!=NULL){
|
||||
ms_mutex_unlock(&s->mutex);
|
||||
if (om!=NULL) freemsg(om);
|
||||
om=m;
|
||||
ms_mutex_lock(&s->mutex);
|
||||
}
|
||||
ms_mutex_unlock(&s->mutex);
|
||||
}
|
||||
if (om!=NULL){
|
||||
timestamp=obj->ticker->time*90;/* rtp uses a 90000 Hz clockrate for video*/
|
||||
mblk_set_timestamp_info(om,timestamp);
|
||||
ms_queue_put(obj->outputs[0],om);
|
||||
}
|
||||
s->frame_count++;
|
||||
}
|
||||
}
|
||||
|
||||
static int vfw_set_fps(MSFilter *f, void *arg){
|
||||
VfwState *s=(VfwState*)f->data;
|
||||
s->fps=*((float*)arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfw_get_pix_fmt(MSFilter *f,void *arg){
|
||||
VfwState *s=(VfwState*)f->data;
|
||||
MSPixFmt fmt=vfw_engine_get_pix_fmt(s->eng);
|
||||
*((MSPixFmt*)arg)=fmt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfw_set_vsize(MSFilter *f, void *arg){
|
||||
VfwState *s=(VfwState*)f->data;
|
||||
s->vsize=*((MSVideoSize*)arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfw_get_vsize(MSFilter *f, void *arg){
|
||||
VfwState *s=(VfwState*)f->data;
|
||||
MSVideoSize *vs=(MSVideoSize*)arg;
|
||||
*vs=vfw_engine_get_video_size(s->eng);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MSFilterMethod methods[]={
|
||||
{ MS_FILTER_SET_FPS , vfw_set_fps },
|
||||
{ MS_FILTER_GET_PIX_FMT , vfw_get_pix_fmt },
|
||||
{ MS_FILTER_SET_VIDEO_SIZE, vfw_set_vsize },
|
||||
{ MS_FILTER_GET_VIDEO_SIZE, vfw_get_vsize },
|
||||
{ 0 , NULL }
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
MSFilterDesc ms_vfw_desc={
|
||||
MS_VFW_ID,
|
||||
"MSVfw",
|
||||
"A video for windows (vfw.h) based source filter to grab pictures.",
|
||||
MS_FILTER_OTHER,
|
||||
NULL,
|
||||
0,
|
||||
1,
|
||||
vfw_init,
|
||||
vfw_preprocess,
|
||||
vfw_process,
|
||||
vfw_postprocess,
|
||||
vfw_uninit,
|
||||
methods
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
MSFilterDesc ms_vfw_desc={
|
||||
.id=MS_VFW_ID,
|
||||
.name="MSVfw",
|
||||
.text="A video for windows (vfw.h) based source filter to grab pictures.",
|
||||
.ninputs=0,
|
||||
.noutputs=1,
|
||||
.category=MS_FILTER_OTHER,
|
||||
.init=vfw_init,
|
||||
.preprocess=vfw_preprocess,
|
||||
.process=vfw_process,
|
||||
.postprocess=vfw_postprocess,
|
||||
.uninit=vfw_uninit,
|
||||
.methods=methods
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
MS_FILTER_DESC_EXPORT(ms_vfw_desc)
|
||||
|
||||
static void ms_vfw_detect(MSWebCamManager *obj);
|
||||
|
||||
static void ms_vfw_cam_init(MSWebCam *cam){
|
||||
}
|
||||
|
||||
|
||||
static MSFilter *ms_vfw_create_reader(MSWebCam *obj){
|
||||
MSFilter *f= ms_filter_new_from_desc(&ms_vfw_desc);
|
||||
VfwState *s=(VfwState*)f->data;
|
||||
s->eng=(VfwEngine*)obj->data;
|
||||
return f;
|
||||
}
|
||||
|
||||
MSWebCamDesc ms_vfw_cam_desc={
|
||||
"VideoForWindows grabber",
|
||||
&ms_vfw_detect,
|
||||
&ms_vfw_cam_init,
|
||||
&ms_vfw_create_reader,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void ms_vfw_detect(MSWebCamManager *obj){
|
||||
int i;
|
||||
MSWebCam *cam;
|
||||
for (i = 0; i < VFW_ENGINE_MAX_INSTANCES; i++){
|
||||
VfwEngine *eng;
|
||||
if ((eng=vfw_engine_new(i))!=NULL){
|
||||
cam=ms_web_cam_new(&ms_vfw_cam_desc);
|
||||
cam->data=(void*)eng;/*store the engine */
|
||||
cam->name=ms_strdup(eng->dev);
|
||||
ms_web_cam_manager_add_cam(obj,cam);
|
||||
}
|
||||
}
|
||||
atexit(vfw_engines_free);
|
||||
}
|
||||
|
||||
Loading…
Add table
Reference in a new issue