Commit 6b90c8b6 authored by jehan's avatar jehan
Browse files

Merge branch 'master' of git.linphone.org:/mediastreamer2

parents c58ad255 7ab88038
......@@ -166,7 +166,7 @@ AC_DEFUN([MS_CHECK_VIDEO],[
fi
AC_ARG_ENABLE(xv,
[ --enable-xv Enable xv supportl],
[ --enable-xv Enable xv support],
[case "${enableval}" in
yes) enable_xv=true ;;
no) enable_xv=false ;;
......@@ -183,6 +183,25 @@ AC_DEFUN([MS_CHECK_VIDEO],[
AC_MSG_ERROR([No X video output API found. Please install X11+Xv headers.])
fi
fi
AC_ARG_ENABLE(gl,
[ --enable-gl Enable GL rendering support (require glx and glew)],
[case "${enableval}" in
yes) enable_gl=true ;;
no) enable_gl=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-gl) ;;
esac],[enable_gl=false])
if test "$enable_gl" = "true"; then
AC_CHECK_HEADERS(GL/gl.h,[] ,[enable_gl=false])
AC_CHECK_HEADERS(GL/glx.h,[] ,[enable_gl=false],[
#include <GL/glx.h>
])
if test "$enable_gl" = "false" ; then
AC_MSG_ERROR([No GL/GLX API found. Please install GL and GLX headers.])
fi
AC_CHECK_HEADERS(X11/Xlib.h)
AC_CHECK_HEADERS(GL/glew.h)
fi
fi
AC_ARG_ENABLE(theora,
......@@ -241,6 +260,13 @@ AC_DEFUN([MS_CHECK_VIDEO],[
if test "$ios_found" = "yes" ; then
LIBS="$LIBS -framework AVFoundation -framework CoreVideo -framework CoreMedia"
fi
if test "$enable_gl" = "true"; then
VIDEO_LIBS="$VIDEO_LIBS -lGL -lGLEW"
VIDEO_CFLAGS="$VIDEO_CFLAGS $SDL_CFLAGS -DHAVE_GL"
fi
if test "$enable_xv" = "true"; then
VIDEO_CFLAGS="$VIDEO_CFLAGS $SDL_CFLAGS -DHAVE_XV"
fi
fi
AC_SUBST(VIDEO_CFLAGS)
......
......@@ -544,6 +544,7 @@ AM_CONDITIONAL(BUILD_WIN32_WCE, test "$mingw32ce_found" = "yes")
AM_CONDITIONAL(BUILD_FFMPEG, test "$ffmpeg" = "true")
AM_CONDITIONAL(BUILD_SDL,test "$sdl_found" = "true" )
AM_CONDITIONAL(BUILD_X11_XV, test "$enable_xv" = "true" )
AM_CONDITIONAL(BUILD_X11_GL, test "$enable_gl" = "true" )
dnl *********************************************
dnl setup oRTP dependency
......
......@@ -132,7 +132,8 @@ typedef enum MSFilterId{
MS_AAL2_G726_16_DEC_ID,
MS_L16_ENC_ID,
MS_L16_DEC_ID,
MS_OSX_GL_DISPLAY_ID
MS_OSX_GL_DISPLAY_ID,
MS_GLXVIDEO_ID
} MSFilterId;
......
......@@ -58,9 +58,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MS_VIDEO_DISPLAY_SHOW_VIDEO \
MS_FILTER_METHOD(MSFilterVideoDisplayInterface,9,int)
#define MS_VIDEO_DISPLAY_ZOOM \
MS_FILTER_METHOD(MSFilterVideoDisplayInterface,10,int[4])
/**Specifiy device orientation from portrait */
#define MS_VIDEO_DISPLAY_SET_DEVICE_ORIENTATION \
MS_FILTER_METHOD(MSFilterVideoDisplayInterface,10,int)
MS_FILTER_METHOD(MSFilterVideoDisplayInterface,11,int)
/**
* Interface definitions for players
......@@ -129,6 +132,8 @@ typedef enum _MSPlayerState MSPlayerState;
MS_FILTER_EVENT_NO_ARG(MSFilterVideoDecoderInterface,0)
#define MS_VIDEO_DECODER_FIRST_IMAGE_DECODED \
MS_FILTER_EVENT_NO_ARG(MSFilterVideoDecoderInterface,1)
#define MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION \
MS_FILTER_METHOD_NO_ARG(MSFilterVideoDecoderInterface, 0)
/** Interface definitions for video capture */
#define MS_VIDEO_CAPTURE_SET_DEVICE_ORIENTATION \
......
......@@ -117,6 +117,18 @@ MS2_PUBLIC void ms_ticker_set_priority(MSTicker *ticker, MSTickerPrio prio);
*/
MS2_PUBLIC int ms_ticker_attach(MSTicker *ticker,MSFilter *f);
/**
* Attach a chain of filters to a ticker.
* The processing chain will be executed until ms_ticker_detach
* will be called.
* This variadic can be used to attach multiple chains in a single call. The argument list MUST be NULL terminated.
*
* @param ticker A #MSTicker object.
* @param f A #MSFilter object.
*
* Returns: 0 if successfull, -1 otherwise.
*/
MS2_PUBLIC int ms_ticker_attach_multiple(MSTicker *ticker,MSFilter *f,...);
/**
* Dettach a chain of filters to a ticker.
* The processing chain will no more be executed.
......
......@@ -319,11 +319,11 @@ MS2_PUBLIC bool_t ms_video_capture_new_frame(MSFrameRateController* ctrl, uint32
struct _MSAverageFPS {
unsigned int last_frame_time, last_print_time;
float mean_inter_frame;
float expected_fps;
const char* context;
};
typedef struct _MSAverageFPS MSAverageFPS;
MS2_PUBLIC void ms_video_init_average_fps(MSAverageFPS* afps, float expectedFps);
MS2_PUBLIC void ms_video_update_average_fps(MSAverageFPS* afps, uint32_t current_time);
MS2_PUBLIC void ms_video_init_average_fps(MSAverageFPS* afps, const char* context);
MS2_PUBLIC bool_t ms_video_update_average_fps(MSAverageFPS* afps, uint32_t current_time);
#ifdef __cplusplus
}
......
......@@ -13,11 +13,11 @@ 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 msjava.c $(ANDROID_SRC_FILES) \
$(GITVERSION_FILE)
$(GITVERSION_FILE) yuv2rgb.fs yuv2rgb.vs
BUILT_SOURCES=alldescs.h $(GITVERSION_FILE)
BUILT_SOURCES=alldescs.h $(GITVERSION_FILE) yuv2rgb.fs.h yuv2rgb.vs.h
CLEANFILES=alldescs.h filterdescs.txt $(GITVERSION_FILE)
CLEANFILES=alldescs.h filterdescs.txt $(GITVERSION_FILE) yuv2rgb.fs.h yuv2rgb.vs.h
INCLUDES=-I$(top_srcdir)/include/
......@@ -128,11 +128,13 @@ endif
if BUILD_VIDEO
if BUILD_MACOSX
libmediastreamer_la_SOURCES+=qtcapture.m msosxdisplay.m shaders.c shaders.h opengles_display.c opengles_display.h yuv2rgb.vs.h yuv2rgb.fs.h
libmediastreamer_la_SOURCES+=qtcapture.m msosxdisplay.m shaders.c shaders.h opengles_display.c opengles_display.h
nodist_libmediastreamer_la_SOURCES = yuv2rgb.fs.h yuv2rgb.fs.h
endif
if BUILD_IOS
libmediastreamer_la_SOURCES+=scaler.c iosdisplay.m ioscapture.m shaders.c shaders.h opengles_display.c opengles_display.h yuv2rgb.vs.h yuv2rgb.fs.h
libmediastreamer_la_SOURCES+=scaler.c iosdisplay.m ioscapture.m shaders.c shaders.h opengles_display.c opengles_display.h
nodist_libmediastreamer_la_SOURCES = yuv2rgb.fs.h yuv2rgb.fs.h
endif
if BUILD_V4L1
libmediastreamer_la_SOURCES+=msv4l.c
......@@ -158,7 +160,6 @@ if BUILD_FFMPEG
libmediastreamer_la_SOURCES+= videoenc.c \
videodec.c \
swscale.h ffmpeg-priv.h \
h264dec.c \
jpegwriter.c
endif
......@@ -170,6 +171,10 @@ if BUILD_X11_XV
libmediastreamer_la_SOURCES+=x11video.c
endif
if BUILD_X11_GL
libmediastreamer_la_SOURCES+=glxvideo.c opengles_display.c shaders.c
endif
libmediastreamer_la_SOURCES+= rfc2429.h \
pixconv.c \
sizeconv.c \
......@@ -280,6 +285,16 @@ make_gitversion_h:
$(GITVERSION_FILE): make_gitversion_h
yuv2rgb.fs.h: yuv2rgb.fs
builddir=`pwd` && \
cd $(top_srcdir)/src && \
xxd -i yuv2rgb.fs | sed s/}\;/,0x00}\;/ > $$builddir/yuv2rgb.fs.h
yuv2rgb.vs.h: yuv2rgb.vs
builddir=`pwd` && \
cd $(top_srcdir)/src && \
xxd -i yuv2rgb.vs | sed s/}\;/,0x00}\;/ > $$builddir/yuv2rgb.vs.h
......
......@@ -72,7 +72,7 @@ static bool_t read_event(MSEventQueue *q){
f=(MSFilter *)*(long*)(q->rptr);
id=(unsigned int)*(long*)(q->rptr+8);
argsize=id & 0xffff;
argsize=id & 0xff;
evsize=argsize+16;
data=q->rptr+16;
if (f->notify!=NULL)
......
/* indent-tabs-mode: t
* vi: set noexpandtab:
* :noTabs=false:
*/
/*
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.
*/
#ifdef HAVE_CONFIG_H
#include "mediastreamer-config.h"
#endif
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/msvideo.h"
#include "layouts.h"
#include <X11/Xlib.h>
#include "opengles_display.h"
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glx.h>
static void glxvideo_unprepare(MSFilter *f);
static bool_t createX11GLWindow(Display* display, MSVideoSize size, GLXContext* ctx, Window* win);
typedef struct GLXVideo
{
MSVideoSize vsize;
MSVideoSize wsize; /*wished window size */
Display *display;
Window window_id;
GLXContext glContext;
struct opengles_display *glhelper;
bool_t show;
bool_t own_window;
bool_t ready;
} GLXVideo;
static Display *init_display(){
const char *display;
Display *ret;
display=getenv("DISPLAY");
if (display==NULL) display=":0";
ret=XOpenDisplay(display);
if (ret==NULL){
ms_error("Could not open display %s",display);
}
return ret;
}
static void glxvideo_init(MSFilter *f){
GLXVideo *obj=(GLXVideo*)ms_new0(GLXVideo,1);
MSVideoSize def_size;
def_size.width=MS_VIDEO_SIZE_CIF_W;
def_size.height=MS_VIDEO_SIZE_CIF_H;
obj->display=init_display();
obj->own_window=FALSE;
obj->ready=FALSE;
obj->vsize=def_size; /* the size of the main video*/
obj->wsize=def_size; /* the size of the window*/
obj->show=TRUE;
f->data=obj;
}
static void glxvideo_uninit(MSFilter *f){
GLXVideo *obj=(GLXVideo*)f->data;
glxvideo_unprepare(f);
if (obj->own_window){
XDestroyWindow(obj->display,obj->window_id);
}
if (obj->display){
XCloseDisplay(obj->display);
obj->display=NULL;
}
ms_free(obj);
}
static void glxvideo_prepare(MSFilter *f){
GLXVideo *s=(GLXVideo*)f->data;
XWindowAttributes wa;
if (s->display==NULL) return;
if (s->window_id==0){
if (createX11GLWindow(s->display, s->wsize, &s->glContext, &s->window_id)) {
GLenum err;
s->glhelper = ogl_display_new();
glXMakeCurrent( s->display, s->window_id, s->glContext );
err = glewInit();
if (err != GLEW_OK) {
ms_error("Failed to initialize GLEW");
return;
} else if (!GLEW_VERSION_2_0) {
ms_error("Need OpenGL 2.0+");
return;
} else {
ogl_display_init(s->glhelper, s->wsize.width, s->wsize.height);
}
}
if (s->window_id==0) return;
s->own_window=TRUE;
}else if (s->own_window==FALSE){
/*we need to register for resize events*/
XSelectInput(s->display,s->window_id,StructureNotifyMask);
}
XGetWindowAttributes(s->display,s->window_id,&wa);
ms_message("glxvideo_prepare(): Window has size %ix%i, received video is %ix%i",wa.width,wa.height,s->vsize.width,s->vsize.height);
if (wa.width<MS_LAYOUT_MIN_SIZE || wa.height<MS_LAYOUT_MIN_SIZE){
return;
}
s->wsize.width=wa.width;
s->wsize.height=wa.height;
s->ready=TRUE;
}
static void glxvideo_unprepare(MSFilter *f){
GLXVideo *s=(GLXVideo*)f->data;
s->ready=FALSE;
}
static void glxvideo_preprocess(MSFilter *f){
GLXVideo *obj=(GLXVideo*)f->data;
if (obj->show) {
if (obj->ready) glxvideo_unprepare(f);
glxvideo_prepare(f);
}
}
static void glxvideo_process(MSFilter *f){
GLXVideo *obj=(GLXVideo*)f->data;
mblk_t *inm;
MSPicture src={0};
XWindowAttributes wa;
XGetWindowAttributes(obj->display,obj->window_id,&wa);
if (wa.width!=obj->wsize.width || wa.height!=obj->wsize.height){
ms_warning("Resized to %ix%i", wa.width,wa.height);
obj->wsize.width=wa.width;
obj->wsize.height=wa.height;
ogl_display_init(obj->glhelper, wa.width, wa.height);
}
ms_filter_lock(f);
if (!obj->show) {
goto end;
}
if (!obj->ready) glxvideo_prepare(f);
if (!obj->ready){
goto end;
}
glXMakeCurrent( obj->display, obj->window_id, obj->glContext );
if (f->inputs[0]!=NULL && (inm=ms_queue_peek_last(f->inputs[0]))!=0) {
if (ms_yuv_buf_init_from_mblk(&src,inm)==0){
ogl_display_set_yuv_to_display(obj->glhelper, inm);
}
}
if (f->inputs[1]!=NULL && (inm=ms_queue_peek_last(f->inputs[1]))!=0) {
if (ms_yuv_buf_init_from_mblk(&src,inm)==0){
ogl_display_set_preview_yuv_to_display(obj->glhelper, inm);
}
}
ogl_display_render(obj->glhelper, 0);
glXSwapBuffers ( obj->display, obj->window_id );
end:
ms_filter_unlock(f);
if (f->inputs[0]!=NULL)
ms_queue_flush(f->inputs[0]);
if (f->inputs[1]!=NULL)
ms_queue_flush(f->inputs[1]);
}
static int glxvideo_set_vsize(MSFilter *f,void *arg){
GLXVideo *s=(GLXVideo*)f->data;
ms_filter_lock(f);
s->wsize=*(MSVideoSize*)arg;
ms_filter_unlock(f);
return 0;
}
static int glxvideo_show_video(MSFilter *f, void *arg){
GLXVideo *s=(GLXVideo*)f->data;
bool_t show=*(bool_t*)arg;
s->show=show?TRUE:FALSE;
if (s->show==FALSE) {
ms_filter_lock(f);
glxvideo_unprepare(f);
ms_filter_unlock(f);
}
return 0;
}
static int glxvideo_zoom(MSFilter *f, void *arg){
GLXVideo *s=(GLXVideo*)f->data;
ms_filter_lock(f);
ogl_display_zoom(s->glhelper, ((int*)arg)[0], ((int*)arg)[1], ((int*)arg)[2], ((int*)arg)[3]);
ms_filter_unlock(f);
return 0;
}
static int glxvideo_get_native_window_id(MSFilter *f, void*arg){
GLXVideo *s=(GLXVideo*)f->data;
unsigned long *id=(unsigned long*)arg;
*id=s->window_id;
return 0;
}
static int glxvideo_set_native_window_id(MSFilter *f, void*arg){
ms_error("MSGLXVideo: cannot change native window");
return 0;
}
static bool_t createX11GLWindow(Display* display, MSVideoSize size, GLXContext* ctx, Window* win) {
static int visual_attribs[] =
{
GLX_X_RENDERABLE , True,
GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
GLX_RENDER_TYPE , GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
GLX_RED_SIZE , 8,
GLX_GREEN_SIZE , 8,
GLX_BLUE_SIZE , 8,
GLX_ALPHA_SIZE , 8,
GLX_DEPTH_SIZE , 24,
GLX_STENCIL_SIZE , 8,
GLX_DOUBLEBUFFER , True,
//GLX_SAMPLE_BUFFERS , 1,
//GLX_SAMPLES , 4,
None
};
int glx_major, glx_minor;
// FBConfigs were added in GLX version 1.3.
if ( !glXQueryVersion( display, &glx_major, &glx_minor ) || ( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) ) {
ms_error( "Invalid GLX version" );
return FALSE;
}
ms_message( "Getting matching framebuffer configs" );
int fbcount;
GLXFBConfig *fbc = glXChooseFBConfig( display, DefaultScreen( display ),
visual_attribs, &fbcount );
if ( !fbc ) {
ms_error( "Failed to retrieve a framebuffer config" );
return FALSE;
}
ms_message( "Found %d matching FB configs.", fbcount );
// Pick the FB config/visual with the most samples per pixel
ms_message( "Getting XVisualInfos" );
int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999;
int i;
for ( i = 0; i < fbcount; i++ ) {
XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[i] );
if ( vi ) {
int samp_buf, samples;
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf );
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLES , &samples );
ms_message( " Matching fbconfig %d, visual ID 0x%lu: SAMPLE_BUFFERS = %d,"
" SAMPLES = %d",
i, vi -> visualid, samp_buf, samples );
if ( best_fbc < 0 || (samp_buf && samples > best_num_samp) )
best_fbc = i, best_num_samp = samples;
if ( worst_fbc < 0 || (!samp_buf || samples < worst_num_samp) )
worst_fbc = i, worst_num_samp = samples;
}
XFree( vi );
}
GLXFBConfig bestFbc = fbc[ best_fbc ];
// Be sure to free the FBConfig list allocated by glXChooseFBConfig()
XFree( fbc );
// Get a visual
XVisualInfo *vi = glXGetVisualFromFBConfig( display, bestFbc );
ms_message( "Chosen visual ID = 0x%lu", vi->visualid );
ms_message( "Creating colormap" );
XSetWindowAttributes swa;
Colormap cmap;
swa.colormap = cmap = XCreateColormap( display,
RootWindow( display, vi->screen ),
vi->visual, AllocNone );
swa.background_pixmap = None ;
swa.border_pixel = 0;
swa.event_mask = StructureNotifyMask;
ms_message( "Creating window" );
*win = XCreateWindow( display, RootWindow( display, vi->screen ),
200, 200, size.width, size.height, 0, vi->depth, InputOutput,
vi->visual,
CWBorderPixel|CWColormap|CWEventMask, &swa );
if ( !(*win) ) {
ms_error( "Failed to create window." );
return FALSE;
}
// Done with the visual info data
XFree( vi );
XStoreName( display, *win, "Video" );
ms_message( "Mapping window" );
XMapWindow( display, *win );
// Get the default screen's GLX extension list
*ctx = glXCreateNewContext( display, bestFbc, GLX_RGBA_TYPE, 0, True );
// Sync to ensure any errors generated are processed.
XSync( display, False );
if (!(*ctx)) {
ms_error("GL context creation failed");
return FALSE;
}
return TRUE;
}
static MSFilterMethod methods[]={
{ MS_FILTER_SET_VIDEO_SIZE , glxvideo_set_vsize },
{ MS_VIDEO_DISPLAY_GET_NATIVE_WINDOW_ID , glxvideo_get_native_window_id },
{ MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID , glxvideo_set_native_window_id },
{ MS_VIDEO_DISPLAY_SHOW_VIDEO , glxvideo_show_video },
{ MS_VIDEO_DISPLAY_ZOOM, glxvideo_zoom },
{ 0 ,NULL}
};
MSFilterDesc ms_glxvideo_desc={
.id=MS_GLXVIDEO_ID,
.name="MSGLXVideo",
.text="A video display using GL (glx)",
.category=MS_FILTER_OTHER,
.ninputs=2,
.noutputs=0,
.init=glxvideo_init,
.preprocess=glxvideo_preprocess,
.process=glxvideo_process,
.uninit=glxvideo_uninit,
.methods=methods
};
MS_FILTER_DESC_EXPORT(ms_glxvideo_desc)
......@@ -39,7 +39,7 @@ typedef struct _DecData{
uint8_t *bitstream;
int bitstream_size;
uint64_t last_error_reported_time;
bool_t first_image_decoded;
bool_t first_image_decoded;
}DecData;
static void ffmpeg_init(){
......@@ -82,8 +82,8 @@ static void dec_init(MSFilter *f){
}
static void dec_preprocess(MSFilter* f) {
DecData *s=(DecData*)f->data;
s->first_image_decoded = FALSE;
DecData *s=(DecData*)f->data;
s->first_image_decoded = FALSE;
}
static void dec_reinit(DecData *d){
......@@ -280,10 +280,10 @@ static void dec_process(MSFilter *f){
}
if (got_picture) {
ms_queue_put(f->outputs[0],get_as_yuvmsg(f,d,&orig));
if (!d->first_image_decoded) {
ms_filter_notify_no_arg(f,MS_VIDEO_DECODER_FIRST_IMAGE_DECODED);
d->first_image_decoded = TRUE;
}
if (!d->first_image_decoded) {
ms_filter_notify_no_arg(f,MS_VIDEO_DECODER_FIRST_IMAGE_DECODED);
d->first_image_decoded = TRUE;
}
}
p+=len;
}
......@@ -312,8 +312,15 @@ static int dec_add_fmtp(MSFilter *f, void *arg){
return 0;
}
static int reset_first_image(MSFilter* f, void *data) {
DecData *d=(DecData*)f->data;
d->first_image_decoded = FALSE;
return 0;
}