From affe39c2d28ae275814c33c3b3378f3668ad4162 Mon Sep 17 00:00:00 2001 From: Liong Sauw Ming Date: Wed, 24 Aug 2011 05:54:25 +0000 Subject: Re #1334: * Removed support for SDL 1.2 * Add job queue inside SDL git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3718 74dad513-b988-da41-8d7b-12977e46ad98 --- aconfigure | 5 +- aconfigure.ac | 4 +- pjmedia/src/pjmedia-videodev/sdl_dev.c | 1184 ++++++++++++++------------------ 3 files changed, 524 insertions(+), 669 deletions(-) diff --git a/aconfigure b/aconfigure index f45b14ab..beb7059c 100755 --- a/aconfigure +++ b/aconfigure @@ -12092,13 +12092,16 @@ echo "${ECHO_T}Using SDL prefix... $with_sdl" >&6; } { echo "$as_me:$LINENO: checking SDL availability.." >&5 echo $ECHO_N "checking SDL availability..... $ECHO_C" >&6; } - if $SDL_CONFIG --version; then + if (sh -c "$SDL_CONFIG --version" | grep 1.3) then ac_sdl_cflags=`$SDL_CONFIG --cflags` ac_sdl_cflags="-DPJMEDIA_VIDEO_DEV_HAS_SDL=1 $ac_sdl_cflags" ac_sdl_ldflags=`$SDL_CONFIG --libs` LIBS="$LIBS $ac_sdl_ldflags" + else + { echo "$as_me:$LINENO: result: Unsupported SDL version" >&5 +echo "${ECHO_T}Unsupported SDL version" >&6; } fi fi diff --git a/aconfigure.ac b/aconfigure.ac index d055e826..771fd6a0 100644 --- a/aconfigure.ac +++ b/aconfigure.ac @@ -793,13 +793,15 @@ AC_ARG_ENABLE(sdl, fi AC_MSG_CHECKING([SDL availability..]) - if $SDL_CONFIG --version; then + if (sh -c "$SDL_CONFIG --version" | grep 1.3) then AC_SUBST(ac_sdl_cflags) AC_SUBST(ac_sdl_ldflags) ac_sdl_cflags=`$SDL_CONFIG --cflags` ac_sdl_cflags="-DPJMEDIA_VIDEO_DEV_HAS_SDL=1 $ac_sdl_cflags" ac_sdl_ldflags=`$SDL_CONFIG --libs` LIBS="$LIBS $ac_sdl_ldflags" + else + AC_MSG_RESULT([Unsupported SDL version]) fi ]) diff --git a/pjmedia/src/pjmedia-videodev/sdl_dev.c b/pjmedia/src/pjmedia-videodev/sdl_dev.c index c08ce2e1..d9b1305c 100644 --- a/pjmedia/src/pjmedia-videodev/sdl_dev.c +++ b/pjmedia/src/pjmedia-videodev/sdl_dev.c @@ -16,7 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include @@ -24,16 +23,6 @@ #if defined(PJMEDIA_VIDEO_DEV_HAS_SDL) && PJMEDIA_VIDEO_DEV_HAS_SDL != 0 -#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 -# include "TargetConditionals.h" -# include -# define SDL_USE_ONE_THREAD_PER_DISPLAY 1 -#elif defined(PJ_WIN32) && PJ_WIN32 != 0 -# define SDL_USE_ONE_THREAD_PER_DISPLAY 1 -#else -# define SDL_USE_ONE_THREAD_PER_DISPLAY 0 -#endif - #include #include #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL @@ -41,22 +30,21 @@ # define OPENGL_DEV_IDX 1 #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ +#if !(SDL_VERSION_ATLEAST(1,3,0)) +# error "SDL 1.3 or later is required" +#endif + +#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 +# include "TargetConditionals.h" +# include +#endif + #define THIS_FILE "sdl_dev.c" #define DEFAULT_CLOCK_RATE 90000 #define DEFAULT_WIDTH 640 #define DEFAULT_HEIGHT 480 #define DEFAULT_FPS 25 -#if !(SDL_VERSION_ATLEAST(1,3,0)) -# define SDL_PIXELFORMAT_RGBA8888 0 -# define SDL_PIXELFORMAT_RGB24 0 -# define SDL_PIXELFORMAT_BGRA8888 0 -# define SDL_PIXELFORMAT_ABGR8888 0 -# define SDL_PIXELFORMAT_BGR24 0 -# define SDL_PIXELFORMAT_ARGB8888 0 -# define SDL_PIXELFORMAT_RGB24 0 -#endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */ - typedef struct sdl_fmt_info { pjmedia_format_id fmt_id; @@ -97,26 +85,6 @@ static sdl_fmt_info sdl_fmts[] = {PJMEDIA_FORMAT_I422JPEG, SDL_YV12_OVERLAY, 0, 0, 0, 0} , }; -#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 -@interface SDLDelegate: NSObject -{ - @public - struct sdl_stream *strm; - struct sdl_factory *sf; - pjmedia_event_type ev_type; - pj_status_t status; -} - -- (void)sdl_init; -- (void)sdl_quit; -- (void)detect_fmt_change; -- (void)sdl_create; -- (void)sdl_destroy; -- (void)handle_event; -- (void)put_frame; -@end -#endif /* PJ_DARWINOS */ - /* sdl_ device info */ struct sdl_dev_info { @@ -130,6 +98,47 @@ struct stream_list struct sdl_stream *stream; }; +#define MAX_JOBS 8 + +typedef pj_status_t (*job_func_ptr)(void *data); + +typedef struct job { + job_func_ptr func; + void *data; + unsigned flags; + pj_status_t retval; +} job; + +#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 +@interface JQDelegate: NSObject +{ + @public + job *pjob; +} + +- (void)run_job; +@end + +@implementation JQDelegate +- (void)run_job +{ + pjob->retval = (*pjob->func)(pjob->data); +} +@end +#endif /* PJ_DARWINOS */ + +typedef struct job_queue { + job *jobs[MAX_JOBS]; + pj_sem_t *job_sem[MAX_JOBS]; + pj_mutex_t *mutex; + pj_thread_t *thread; + pj_sem_t *sem; + + int head, tail; + pj_bool_t is_full; + pj_bool_t is_quitting; +} job_queue; + /* sdl_ factory */ struct sdl_factory { @@ -139,13 +148,15 @@ struct sdl_factory unsigned dev_count; struct sdl_dev_info *dev_info; + job_queue *jq; pj_thread_t *sdl_thread; /**< SDL thread. */ - pj_status_t status; pj_sem_t *sem; pj_mutex_t *mutex; struct stream_list streams; pj_bool_t is_quitting; + pj_thread_desc thread_desc; + pj_thread_t *ev_thread; }; /* Video stream. */ @@ -158,48 +169,26 @@ struct sdl_stream pjmedia_vid_dev_cb vid_cb; /**< Stream callback. */ void *user_data; /**< Application data. */ - pj_thread_t *sdl_thread; /**< SDL thread. */ - pj_bool_t is_initialized; - pj_bool_t is_quitting; - pj_bool_t is_destroyed; + struct sdl_factory *sf; + const pjmedia_frame *frame; pj_bool_t is_running; - pj_bool_t render_exited; - pj_status_t status; - pjmedia_format *new_fmt; - pjmedia_rect_size *new_disp_size; pj_timestamp last_ts; - pjmedia_frame frame; - pj_size_t frame_buf_size; struct stream_list list_entry; - struct sdl_factory *sf; -#if SDL_VERSION_ATLEAST(1,3,0) SDL_Window *window; /**< Display window. */ SDL_Renderer *renderer; /**< Display renderer. */ SDL_Texture *scr_tex; /**< Screen texture. */ int pitch; /**< Pitch value. */ -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ SDL_Rect rect; /**< Frame rectangle. */ SDL_Rect dstrect; /**< Display rectangle. */ - SDL_Surface *screen; /**< Display screen. */ - SDL_Surface *surf; /**< RGB surface. */ - SDL_Overlay *overlay; /**< YUV overlay. */ #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL -# if SDL_VERSION_ATLEAST(1,3,0) SDL_GLContext *gl_context; -# endif /* SDL_VERSION_ATLEAST(1,3,0) */ GLuint texture; #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ pjmedia_video_apply_fmt_param vafp; }; -struct sdl_dev_t -{ - struct sdl_factory *sf; - struct sdl_stream *strm; -}; - /* Prototypes */ static pj_status_t sdl_factory_init(pjmedia_vid_dev_factory *f); static pj_status_t sdl_factory_destroy(pjmedia_vid_dev_factory *f); @@ -233,7 +222,16 @@ static pj_status_t sdl_stream_start(pjmedia_vid_dev_stream *strm); static pj_status_t sdl_stream_stop(pjmedia_vid_dev_stream *strm); static pj_status_t sdl_stream_destroy(pjmedia_vid_dev_stream *strm); -static int sdl_thread(void * data); +static pj_status_t resize_disp(struct sdl_stream *strm, + pjmedia_rect_size *new_disp_size); +static pj_status_t sdl_destroy_all(void *data); + +/* Job queue prototypes */ +static pj_status_t job_queue_create(pj_pool_t *pool, job_queue **pjq); +static pj_status_t job_queue_post_job(job_queue *jq, job_func_ptr func, + void *data, unsigned flags, + pj_status_t *retval); +static pj_status_t job_queue_destroy(job_queue *jq); /* Operations */ static pjmedia_vid_dev_factory_op factory_op = @@ -280,16 +278,174 @@ pjmedia_vid_dev_factory* pjmedia_sdl_factory(pj_pool_factory *pf) return &f->base; } +static pj_status_t sdl_init(void * data) +{ + PJ_UNUSED_ARG(data); + + if (SDL_Init(SDL_INIT_VIDEO)) { + PJ_LOG(3, (THIS_FILE, "Failed initializing SDL")); + return PJMEDIA_EVID_INIT; + } + + return PJ_SUCCESS; +} + +static struct sdl_stream* find_stream(struct sdl_factory *sf, + Uint32 windowID, + pjmedia_event *pevent) +{ + struct stream_list *it, *itBegin; + struct sdl_stream *strm = NULL; + + itBegin = &sf->streams; + for (it = itBegin->next; it != itBegin; it = it->next) { + if (SDL_GetWindowID(it->stream->window) == windowID) + { + strm = it->stream; + break; + } + } + + if (strm) + pjmedia_event_init(pevent, PJMEDIA_EVENT_NONE, &strm->last_ts, + &strm->base.epub); + + return strm; +} + +static pj_status_t handle_event(void *data) +{ + struct sdl_factory *sf = (struct sdl_factory*)data; + SDL_Event sevent; + + if (!pj_thread_is_registered()) + pj_thread_register("sdl_ev", sf->thread_desc, &sf->ev_thread); + + while (SDL_PollEvent(&sevent)) { + struct sdl_stream *strm = NULL; + pjmedia_event pevent; + + pj_mutex_lock(sf->mutex); + pevent.type = PJMEDIA_EVENT_NONE; + switch(sevent.type) { + case SDL_MOUSEBUTTONDOWN: + strm = find_stream(sf, sevent.button.windowID, &pevent); + pevent.type = PJMEDIA_EVENT_MOUSE_BTN_DOWN; + break; + case SDL_WINDOWEVENT: + strm = find_stream(sf, sevent.window.windowID, &pevent); + switch (sevent.window.event) { + case SDL_WINDOWEVENT_RESIZED: + pevent.type = PJMEDIA_EVENT_WND_RESIZED; + pevent.data.wnd_resized.new_size.w = + sevent.window.data1; + pevent.data.wnd_resized.new_size.h = + sevent.window.data2; + break; + case SDL_WINDOWEVENT_CLOSE: + pevent.type = PJMEDIA_EVENT_WND_CLOSING; + break; + } + break; + default: + break; + } + + if (strm && pevent.type != PJMEDIA_EVENT_NONE) { + pj_status_t status; + + pjmedia_event_publish(&strm->base.epub, &pevent); + + switch (pevent.type) { + case PJMEDIA_EVENT_WND_RESIZED: + status = resize_disp(strm, &pevent.data.wnd_resized.new_size); + if (status != PJ_SUCCESS) + PJ_LOG(3, (THIS_FILE, "Failed resizing the display.")); + break; + case PJMEDIA_EVENT_WND_CLOSING: + if (pevent.data.wnd_closing.cancel) { + /* Cancel the closing operation */ + break; + } + + /* Proceed to cleanup SDL. App must still call + * pjmedia_dev_stream_destroy() when getting WND_CLOSED + * event + */ + sdl_stream_stop(&strm->base); + sdl_destroy_all(strm); + pjmedia_event_init(&pevent, PJMEDIA_EVENT_WND_CLOSED, + &strm->last_ts, + &strm->base.epub); + pjmedia_event_publish(&strm->base.epub, &pevent); + + /* + * Note: don't access the stream after this point, it + * might have been destroyed + */ + break; + default: + /* Just to prevent gcc warning about unused enums */ + break; + } + } + + pj_mutex_unlock(sf->mutex); + } + + return PJ_SUCCESS; +} + +static int sdl_ev_thread(void *data) +{ + struct sdl_factory *sf = (struct sdl_factory*)data; + + while(1) { + pj_status_t status; + + pj_mutex_lock(sf->mutex); + if (pj_list_empty(&sf->streams)) { + pj_mutex_unlock(sf->mutex); + /* Wait until there is any stream. */ + pj_sem_wait(sf->sem); + } else + pj_mutex_unlock(sf->mutex); + + if (sf->is_quitting) + break; + + job_queue_post_job(sf->jq, handle_event, sf, 0, &status); + + pj_thread_sleep(50); + } + + return 0; +} + +static pj_status_t sdl_quit(void *data) +{ + PJ_UNUSED_ARG(data); + SDL_Quit(); + return PJ_SUCCESS; +} + /* API: init factory */ static pj_status_t sdl_factory_init(pjmedia_vid_dev_factory *f) { struct sdl_factory *sf = (struct sdl_factory*)f; struct sdl_dev_info *ddi; unsigned i, j; - struct sdl_dev_t sdl_dev; pj_status_t status; SDL_version version; + status = job_queue_create(sf->pool, &sf->jq); + if (status != PJ_SUCCESS) + return PJMEDIA_EVID_INIT; + + job_queue_post_job(sf->jq, sdl_init, NULL, 0, &status); + if (status != PJ_SUCCESS) + return status; + pj_list_init(&sf->streams); status = pj_mutex_create_recursive(sf->pool, "sdl_factory", &sf->mutex); @@ -300,20 +456,11 @@ static pj_status_t sdl_factory_init(pjmedia_vid_dev_factory *f) if (status != PJ_SUCCESS) return status; - sf->status = PJ_EUNKNOWN; - sdl_dev.sf = sf; - sdl_dev.strm = NULL; - status = pj_thread_create(sf->pool, "sdl_thread", sdl_thread, - &sdl_dev, 0, 0, &sf->sdl_thread); - if (status != PJ_SUCCESS) { - return PJMEDIA_EVID_INIT; - } - - while (sf->status == PJ_EUNKNOWN) - pj_thread_sleep(10); - - if (sf->status != PJ_SUCCESS) - return sf->status; + /* Create event handler thread. */ + status = pj_thread_create(sf->pool, "sdl_thread", sdl_ev_thread, + sf, 0, 0, &sf->sdl_thread); + if (status != PJ_SUCCESS) + return status; sf->dev_count = 1; #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL @@ -345,9 +492,7 @@ static pj_status_t sdl_factory_init(pjmedia_vid_dev_factory *f) ddi->info.has_callback = PJ_FALSE; ddi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT | PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE; -#if SDL_VERSION_ATLEAST(1,3,0) ddi->info.caps |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW; -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ for (j = 0; j < ddi->info.fmt_cnt; j++) { pjmedia_format *fmt = &ddi->info.fmt[j]; @@ -369,6 +514,7 @@ static pj_status_t sdl_factory_destroy(pjmedia_vid_dev_factory *f) { struct sdl_factory *sf = (struct sdl_factory*)f; pj_pool_t *pool = sf->pool; + pj_status_t status; pj_assert(pj_list_empty(&sf->streams)); @@ -388,6 +534,9 @@ static pj_status_t sdl_factory_destroy(pjmedia_vid_dev_factory *f) sf->sem = NULL; } + job_queue_post_job(sf->jq, sdl_quit, NULL, 0, &status); + job_queue_destroy(sf->jq); + sf->pool = NULL; pj_pool_release(pool); @@ -461,31 +610,20 @@ static sdl_fmt_info* get_sdl_format_info(pjmedia_format_id id) return NULL; } -static void sdl_destroy(struct sdl_stream *strm, pj_bool_t destroy_win) +static pj_status_t sdl_destroy(void *data) { - PJ_UNUSED_ARG(destroy_win); + struct sdl_stream *strm = (struct sdl_stream *)data; - if (strm->surf) { - SDL_FreeSurface(strm->surf); - strm->surf = NULL; - } - if (strm->overlay) { - SDL_FreeYUVOverlay(strm->overlay); - strm->overlay = NULL; - } #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL if (strm->texture) { glDeleteTextures(1, &strm->texture); strm->texture = 0; } -#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ -#if SDL_VERSION_ATLEAST(1,3,0) -# if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL if (strm->gl_context) { SDL_GL_DeleteContext(strm->gl_context); strm->gl_context = NULL; } -# endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ +#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ if (strm->scr_tex) { SDL_DestroyTexture(strm->scr_tex); strm->scr_tex = NULL; @@ -494,26 +632,36 @@ static void sdl_destroy(struct sdl_stream *strm, pj_bool_t destroy_win) SDL_DestroyRenderer(strm->renderer); strm->renderer = NULL; } -# if !defined(TARGET_OS_IPHONE) || TARGET_OS_IPHONE == 0 - if (destroy_win) { - if (strm->window && - !(strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW)) - { - SDL_DestroyWindow(strm->window); - } - strm->window = NULL; + + return PJ_SUCCESS; +} + +static pj_status_t sdl_destroy_all(void *data) +{ + struct sdl_stream *strm = (struct sdl_stream *)data; + + sdl_destroy(data); +#if !defined(TARGET_OS_IPHONE) || TARGET_OS_IPHONE == 0 + if (strm->window && + !(strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW)) + { + SDL_DestroyWindow(strm->window); } -# endif /* TARGET_OS_IPHONE */ -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ + strm->window = NULL; +#endif /* TARGET_OS_IPHONE */ + + return PJ_SUCCESS; } -static pj_status_t sdl_create_view(struct sdl_stream *strm, - pjmedia_format *fmt) +static pj_status_t sdl_create_rend(struct sdl_stream * strm, + pjmedia_format *fmt) { - sdl_fmt_info *sdl_info = get_sdl_format_info(fmt->id); + sdl_fmt_info *sdl_info; const pjmedia_video_format_info *vfi; pjmedia_video_format_detail *vfd; + fmt = &strm->param.fmt; + sdl_info = get_sdl_format_info(fmt->id); vfi = pjmedia_get_video_format_info(pjmedia_video_format_mgr_instance(), fmt->id); if (!vfi || !sdl_info) @@ -536,21 +684,30 @@ static pj_status_t sdl_create_view(struct sdl_stream *strm, strm->dstrect.w = (Uint16)strm->param.disp_size.w; strm->dstrect.h = (Uint16)strm->param.disp_size.h; - sdl_destroy(strm, PJ_FALSE); + sdl_destroy(strm); + +#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL + if (strm->param.rend_id == OPENGL_DEV_IDX) { + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); + } +#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ -#if SDL_VERSION_ATLEAST(1,3,0) if (!strm->window) { - Uint32 flags = SDL_WINDOW_SHOWN | /*SDL_WINDOW_RESIZABLE*/ - SDL_WINDOW_BORDERLESS; + Uint32 flags = /*SDL_WINDOW_RESIZABLE; */ SDL_WINDOW_BORDERLESS; -# if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL + if (!((strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE) && + strm->param.window_hide)) + flags |= SDL_WINDOW_SHOWN; + +#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL if (strm->param.rend_id == OPENGL_DEV_IDX) flags |= SDL_WINDOW_OPENGL; -# endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ +#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ if (strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) { /* Use the window supplied by the application. */ - strm->window = SDL_CreateWindowFrom(strm->param.window.info.window); + strm->window = SDL_CreateWindowFrom( + strm->param.window.info.window); } else { /* Create the window where we will draw. */ strm->window = SDL_CreateWindow("pjmedia-SDL video", @@ -564,9 +721,6 @@ static pj_status_t sdl_create_view(struct sdl_stream *strm, return PJMEDIA_EVID_SYSERR; } - SDL_SetWindowSize(strm->window, strm->param.disp_size.w, - strm->param.disp_size.h); - /** * We must call SDL_CreateRenderer in order for draw calls to * affect this window. @@ -575,36 +729,14 @@ static pj_status_t sdl_create_view(struct sdl_stream *strm, if (!strm->renderer) return PJMEDIA_EVID_SYSERR; -# if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL +#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL if (strm->param.rend_id == OPENGL_DEV_IDX) { strm->gl_context = SDL_GL_CreateContext(strm->window); if (!strm->gl_context) return PJMEDIA_EVID_SYSERR; SDL_GL_MakeCurrent(strm->window, strm->gl_context); - } -# endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ - - strm->screen = SDL_GetWindowSurface(strm->window); - -#else /* SDL_VERSION_ATLEAST(1,3,0) */ - /* Initialize the display */ - strm->screen = SDL_SetVideoMode(strm->param.disp_size.w, - strm->param.disp_size.h, 0, ( -# if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL - strm->param.rend_id == OPENGL_DEV_IDX? - SDL_OPENGL | SDL_RESIZABLE: -# endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ - SDL_RESIZABLE | SDL_SWSURFACE)); - if (strm->screen == NULL) - return PJMEDIA_EVID_SYSERR; - - SDL_WM_SetCaption("pjmedia-SDL video", NULL); -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ - -#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL - if (strm->param.rend_id == OPENGL_DEV_IDX) { - /* Init some OpenGL settings */ + /* Init some OpenGL settings */ glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glEnable(GL_TEXTURE_2D); @@ -628,7 +760,6 @@ static pj_status_t sdl_create_view(struct sdl_stream *strm, return PJMEDIA_EVID_SYSERR; } else #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ -#if SDL_VERSION_ATLEAST(1,3,0) { strm->scr_tex = SDL_CreateTexture(strm->renderer, sdl_info->sdl_format, SDL_TEXTUREACCESS_STREAMING, @@ -638,140 +769,63 @@ static pj_status_t sdl_create_view(struct sdl_stream *strm, strm->pitch = strm->rect.w * SDL_BYTESPERPIXEL(sdl_info->sdl_format); } -#else /* SDL_VERSION_ATLEAST(1,3,0) */ - if (vfi->color_model == PJMEDIA_COLOR_MODEL_RGB) { - strm->surf = SDL_CreateRGBSurface(SDL_SWSURFACE, - strm->rect.w, strm->rect.h, - vfi->bpp, - sdl_info->Rmask, - sdl_info->Gmask, - sdl_info->Bmask, - sdl_info->Amask); - if (strm->surf == NULL) - return PJMEDIA_EVID_SYSERR; - } else if (vfi->color_model == PJMEDIA_COLOR_MODEL_YUV) { - strm->overlay = SDL_CreateYUVOverlay(strm->rect.w, strm->rect.h, - sdl_info->sdl_format, - strm->screen); - if (strm->overlay == NULL) - return PJMEDIA_EVID_SYSERR; - } -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ - - if (strm->vafp.framebytes > strm->frame_buf_size) { - strm->frame_buf_size = strm->vafp.framebytes; - strm->frame.buf = pj_pool_alloc(strm->pool, strm->vafp.framebytes); - } return PJ_SUCCESS; } -static pj_status_t sdl_create(struct sdl_stream *strm) +static pj_status_t sdl_create(void *data) { - strm->is_initialized = PJ_TRUE; + struct sdl_stream *strm = (struct sdl_stream *)data; + return sdl_create_rend(strm, &strm->param.fmt); +} -#if !(SDL_VERSION_ATLEAST(1,3,0)) - if (SDL_Init(SDL_INIT_VIDEO)) { - strm->status = PJMEDIA_EVID_INIT; - return strm->status; +static pj_status_t resize_disp(struct sdl_stream *strm, + pjmedia_rect_size *new_disp_size) +{ + pj_memcpy(&strm->param.disp_size, new_disp_size, + sizeof(strm->param.disp_size)); + + if (strm->scr_tex) { + strm->dstrect.x = strm->dstrect.y = 0; + strm->dstrect.w = (Uint16)strm->param.disp_size.w; + strm->dstrect.h = (Uint16)strm->param.disp_size.h; + SDL_RenderSetViewport(strm->renderer, &strm->dstrect); } -#endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */ - #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL - if (strm->param.rend_id == OPENGL_DEV_IDX) { - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); + else if (strm->param.rend_id == OPENGL_DEV_IDX) { + sdl_create_rend(strm, &strm->param.fmt); } #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ - strm->status = sdl_create_view(strm, &strm->param.fmt); - return strm->status; + return PJ_SUCCESS; } -static void detect_fmt_change(struct sdl_stream *strm) +static pj_status_t change_format(struct sdl_stream *strm, + pjmedia_format *new_fmt) { - strm->status = PJ_SUCCESS; - if (strm->new_fmt || strm->new_disp_size) { - if (strm->new_disp_size) { - pj_memcpy(&strm->param.disp_size, strm->new_disp_size, - sizeof(strm->param.disp_size)); -#if SDL_VERSION_ATLEAST(1,3,0) - if (strm->scr_tex) { - strm->dstrect.x = strm->dstrect.y = 0; - strm->dstrect.w = (Uint16)strm->param.disp_size.w; - strm->dstrect.h = (Uint16)strm->param.disp_size.h; - SDL_RenderSetViewport(strm->renderer, &strm->dstrect); - strm->new_fmt = NULL; - strm->new_disp_size = NULL; - return; - } -#endif - } + pj_status_t status; - /* Re-initialize SDL */ - strm->status = sdl_create_view(strm, (strm->new_fmt? strm->new_fmt : - &strm->param.fmt)); + /* Recreate SDL renderer */ + status = sdl_create_rend(strm, (new_fmt? new_fmt : + &strm->param.fmt)); + if (status == PJ_SUCCESS && new_fmt) + pjmedia_format_copy(&strm->param.fmt, new_fmt); - if (strm->status == PJ_SUCCESS) { - if (strm->new_fmt) - pjmedia_format_copy(&strm->param.fmt, strm->new_fmt); - } - strm->new_fmt = NULL; - strm->new_disp_size = NULL; - } + return status; } -static pj_status_t put_frame(struct sdl_stream *stream, - const pjmedia_frame *frame) +static pj_status_t put_frame(void *data) { - if (!stream->is_running) - return PJ_SUCCESS; + struct sdl_stream *stream = (struct sdl_stream *)data; + const pjmedia_frame *frame = stream->frame; - if (stream->surf) { - if (SDL_MUSTLOCK(stream->surf)) { - if (SDL_LockSurface(stream->surf) < 0) { - PJ_LOG(3, (THIS_FILE, "Unable to lock SDL surface")); - return PJMEDIA_EVID_NOTREADY; - } - } - - pj_memcpy(stream->surf->pixels, frame->buf, - stream->vafp.framebytes); - - if (SDL_MUSTLOCK(stream->surf)) { - SDL_UnlockSurface(stream->surf); - } -#if SDL_VERSION_ATLEAST(1,3,0) - SDL_UpdateWindowSurface(stream->window); -#else /* SDL_VERSION_ATLEAST(1,3,0) */ - SDL_BlitSurface(stream->surf, NULL, stream->screen, &stream->dstrect); -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ - } else if (stream->overlay) { - int i, sz, offset; - - if (SDL_LockYUVOverlay(stream->overlay) < 0) { - PJ_LOG(3, (THIS_FILE, "Unable to lock SDL overlay")); - return PJMEDIA_EVID_NOTREADY; - } - - for (i = 0, offset = 0; i < stream->overlay->planes; i++) { - sz = stream->vafp.plane_bytes[i]; - pj_memcpy(stream->overlay->pixels[i], - (char *)frame->buf + offset, sz); - offset += sz; - } - - SDL_UnlockYUVOverlay(stream->overlay); - SDL_DisplayYUVOverlay(stream->overlay, &stream->dstrect); - } -#if SDL_VERSION_ATLEAST(1,3,0) - else if (stream->scr_tex) { + if (stream->scr_tex) { SDL_UpdateTexture(stream->scr_tex, NULL, frame->buf, stream->pitch); SDL_RenderClear(stream->renderer); SDL_RenderCopy(stream->renderer, stream->scr_tex, &stream->rect, &stream->dstrect); SDL_RenderPresent(stream->renderer); } -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL else if (stream->param.rend_id == OPENGL_DEV_IDX && stream->texture) { glBindTexture(GL_TEXTURE_2D, stream->texture); @@ -787,306 +841,33 @@ static pj_status_t put_frame(struct sdl_stream *stream, glTexCoord2f(1, 1); glVertex2i(stream->param.disp_size.w, stream->param.disp_size.h); glEnd(); -# if SDL_VERSION_ATLEAST(1,3,0) SDL_GL_SwapWindow(stream->window); -# else /* SDL_VERSION_ATLEAST(1,3,0) */ - SDL_GL_SwapBuffers(); -# endif /* SDL_VERSION_ATLEAST(1,3,0) */ } #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ return PJ_SUCCESS; } -static struct sdl_stream* find_stream(struct sdl_factory *sf, - Uint32 windowID, - pjmedia_event *pevent) -{ - struct stream_list *it, *itBegin; - struct sdl_stream *strm = NULL; - - itBegin = &sf->streams; - for (it = itBegin->next; it != itBegin; it = it->next) { -#if SDL_VERSION_ATLEAST(1,3,0) - if (SDL_GetWindowID(it->stream->window) == windowID) -#else /* SDL_VERSION_ATLEAST(1,3,0) */ - PJ_UNUSED_ARG(windowID); -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ - { - strm = it->stream; - break; - } - } - - if (strm) - pjmedia_event_init(pevent, PJMEDIA_EVENT_NONE, &strm->last_ts, - &strm->base.epub); - - return strm; -} - -static int poll_event(struct sdl_factory *sf, pjmedia_event *pevent, - struct sdl_stream **strm) -{ - int retval; - SDL_Event sevent; - - retval = SDL_PollEvent(&sevent); - if (retval) { -#if !(SDL_VERSION_ATLEAST(1,3,0)) - *strm = find_stream(sf, 0, pevent); - pj_assert(strm); -#endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */ - - switch(sevent.type) { - case SDL_MOUSEBUTTONDOWN: -#if SDL_VERSION_ATLEAST(1,3,0) - *strm = find_stream(sf, sevent.button.windowID, pevent); -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ - pevent->type = PJMEDIA_EVENT_MOUSE_BTN_DOWN; - break; -#if SDL_VERSION_ATLEAST(1,3,0) - case SDL_WINDOWEVENT: - *strm = find_stream(sf, sevent.window.windowID, pevent); - switch (sevent.window.event) { - case SDL_WINDOWEVENT_RESIZED: - pevent->type = PJMEDIA_EVENT_WND_RESIZED; - pevent->data.wnd_resized.new_size.w = - sevent.window.data1; - pevent->data.wnd_resized.new_size.h = - sevent.window.data2; - break; - case SDL_WINDOWEVENT_CLOSE: - pevent->type = PJMEDIA_EVENT_WND_CLOSING; - break; - } - break; -#else /* SDL_VERSION_ATLEAST(1,3,0) */ - case SDL_VIDEORESIZE: - pevent->type = PJMEDIA_EVENT_WND_RESIZED; - pevent->data.wnd_resized.new_size.w = sevent.resize.w; - pevent->data.wnd_resized.new_size.h = sevent.resize.h; - break; - case SDL_QUIT: - pevent->type = PJMEDIA_EVENT_WND_CLOSING; - break; -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ - } - } - - return retval; -} - -static struct sdl_stream* handle_event(struct sdl_factory *sf, - struct sdl_stream *rcv_strm, - pjmedia_event_type *ev_type) -{ - struct sdl_stream *strm = NULL; - pjmedia_event pevent; - - *ev_type = PJMEDIA_EVENT_NONE; - while (poll_event(sf, &pevent, &strm)) { - *ev_type = pevent.type; - if (pevent.type != PJMEDIA_EVENT_NONE && strm && - (!rcv_strm || rcv_strm == strm)) - { - pjmedia_event_publish(&strm->base.epub, &pevent); - - switch (pevent.type) { - case PJMEDIA_EVENT_WND_RESIZED: - strm->new_disp_size = &pevent.data.wnd_resized.new_size; - strm->status = PJ_SUCCESS; - detect_fmt_change(strm); - if (strm->status != PJ_SUCCESS) - return strm; - break; - - case PJMEDIA_EVENT_WND_CLOSING: - if (pevent.data.wnd_closing.cancel) { - /* Cancel the closing operation */ - break; - } - - /* Proceed to cleanup SDL. App must still call - * pjmedia_dev_stream_destroy() when getting WND_CLOSED - * event - */ - strm->is_quitting = PJ_TRUE; - sdl_stream_stop(&strm->base); - - return strm; - default: - /* Just to prevent gcc warning about unused enums */ - break; - } - } - } - - return strm; -} - -static int sdl_thread(void * data) -{ - struct sdl_dev_t *sdl_dev = (struct sdl_dev_t *)data; - struct sdl_factory *sf = sdl_dev->sf; - struct sdl_stream *strm = sdl_dev->strm; - -#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 - NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init]; - SDLDelegate *delegate = [[SDLDelegate alloc] init]; -#endif /* PJ_DARWINOS */ - -#if SDL_VERSION_ATLEAST(1,3,0) -# if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 - [delegate performSelectorOnMainThread:@selector(sdl_init) - withObject:nil waitUntilDone:YES]; - if (delegate->status != PJ_SUCCESS) - goto on_error; -# else /* PJ_DARWINOS */ - /* Initialize the SDL library */ - if (SDL_Init(SDL_INIT_VIDEO)) { - sf->status = PJMEDIA_EVID_INIT; - goto on_error; - } -# endif /* PJ_DARWINOS */ -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ - sf->status = PJ_SUCCESS; - - while (!sf->is_quitting) { - struct stream_list *it, *itBegin; - pjmedia_event_type ev_type; - struct sdl_stream *ev_stream; - - pj_mutex_lock(sf->mutex); - - if (!strm && pj_list_empty(&sf->streams)) { - /* Wait until there is any stream. */ - pj_mutex_unlock(sf->mutex); - pj_sem_wait(sf->sem); - pj_mutex_lock(sf->mutex); - } - - itBegin = &sf->streams; - for (it = itBegin->next; it != itBegin; it = it->next) { - if ((strm && it->stream != strm) || it->stream->is_quitting) - continue; - - if (!it->stream->is_initialized) { -#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 - delegate->strm = it->stream; - [delegate performSelectorOnMainThread:@selector(sdl_create) - withObject:nil waitUntilDone:YES]; -#else /* PJ_DARWINOS */ - sdl_create(it->stream); -#endif /* PJ_DARWINOS */ - } - -#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 - delegate->strm = it->stream; - [delegate performSelectorOnMainThread:@selector(detect_fmt_change) - withObject:nil waitUntilDone:YES]; - [delegate performSelectorOnMainThread:@selector(put_frame) - withObject:nil waitUntilDone:YES]; -#else /* PJ_DARWINOS */ - detect_fmt_change(it->stream); - put_frame(it->stream, &it->stream->frame); -#endif /* PJ_DARWINOS */ - } - -#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 - delegate->sf = sf; - delegate->strm = strm; - [delegate performSelectorOnMainThread:@selector(handle_event) - withObject:nil waitUntilDone:YES]; - ev_stream = delegate->strm; - ev_type = delegate->ev_type; -#else /* PJ_DARWINOS */ - ev_stream = handle_event(sf, strm, &ev_type); -#endif /* PJ_DARWINOS */ - - itBegin = &sf->streams; - for (it = itBegin->next; it != itBegin; it = it->next) { - if ((strm && it->stream != strm) || !it->stream->is_quitting || - it->stream->is_destroyed) - continue; - -#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 - delegate->strm = it->stream; - [delegate performSelectorOnMainThread:@selector(sdl_destroy) - withObject:nil waitUntilDone:YES]; -# if !(SDL_VERSION_ATLEAST(1,3,0)) - [delegate performSelectorOnMainThread:@selector(sdl_quit) - withObject:nil waitUntilDone:YES]; -# endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */ -#else /* PJ_DARWINOS */ - sdl_destroy(it->stream, PJ_TRUE); -# if !(SDL_VERSION_ATLEAST(1,3,0)) - SDL_Quit(); -# endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */ -#endif /* PJ_DARWINOS */ - it->stream->screen = NULL; - it->stream->is_destroyed = PJ_TRUE; - - if (ev_type == PJMEDIA_EVENT_WND_CLOSING && - it->stream == ev_stream) - { - pjmedia_event p_event; - - pjmedia_event_init(&p_event, PJMEDIA_EVENT_WND_CLOSED, - &it->stream->last_ts, - &it->stream->base.epub); - pjmedia_event_publish(&it->stream->base.epub, &p_event); - - /* - * Note: don't access the stream after this point, it - * might have been destroyed - */ - } - - if (strm) { - pj_mutex_unlock(sf->mutex); - return 0; - } - } - - pj_mutex_unlock(sf->mutex); - } - -on_error: -#if SDL_VERSION_ATLEAST(1,3,0) -# if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 - [delegate performSelectorOnMainThread:@selector(sdl_quit) - withObject:nil waitUntilDone:YES]; - [delegate release]; - [apool release]; -# else /* PJ_DARWINOS */ - SDL_Quit(); -# endif /* PJ_DARWINOS */ -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ - - return 0; -} - /* API: Put frame from stream */ static pj_status_t sdl_stream_put_frame(pjmedia_vid_dev_stream *strm, const pjmedia_frame *frame) { struct sdl_stream *stream = (struct sdl_stream*)strm; + pj_status_t status; stream->last_ts.u64 = frame->timestamp.u64; - if (!stream->is_running) { - stream->render_exited = PJ_TRUE; - return PJ_SUCCESS; - } + if (!stream->is_running) + return PJ_EINVALIDOP; if (frame->size==0 || frame->buf==NULL || frame->size < stream->vafp.framebytes) return PJ_SUCCESS; - pj_memcpy(stream->frame.buf, frame->buf, stream->vafp.framebytes); - - return PJ_SUCCESS; + stream->frame = frame; + job_queue_post_job(stream->sf->jq, put_frame, strm, 0, &status); + + return status; } /* API: create stream */ @@ -1104,16 +885,6 @@ static pj_status_t sdl_factory_create_stream( PJ_ASSERT_RETURN(param->dir == PJMEDIA_DIR_RENDER, PJ_EINVAL); -#if !SDL_VERSION_ATLEAST(1,3,0) - /* Prior to 1.3, SDL does not support multiple renderers. */ - pj_mutex_lock(sf->mutex); - if (!pj_list_empty(&sf->streams)) { - pj_mutex_unlock(sf->mutex); - return PJMEDIA_EVID_NOTREADY; - } - pj_mutex_unlock(sf->mutex); -#endif - /* Create and Initialize stream descriptor */ pool = pj_pool_create(sf->pf, "sdl-dev", 1000, 1000, NULL); PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM); @@ -1125,46 +896,20 @@ static pj_status_t sdl_factory_create_stream( pj_memcpy(&strm->vid_cb, cb, sizeof(*cb)); strm->user_data = user_data; pjmedia_event_publisher_init(&strm->base.epub, PJMEDIA_SIG_VID_DEV_SDL); - pj_list_init(&strm->list_entry); - strm->list_entry.stream = strm; /* Create render stream here */ if (param->dir & PJMEDIA_DIR_RENDER) { - struct sdl_dev_t sdl_dev; - - strm->status = PJ_SUCCESS; - sdl_dev.sf = strm->sf; - sdl_dev.strm = strm; + job_queue_post_job(sf->jq, sdl_create, strm, 0, &status); + if (status != PJ_SUCCESS) { + goto on_error; + } + pj_list_init(&strm->list_entry); + strm->list_entry.stream = strm; pj_mutex_lock(strm->sf->mutex); -#if !SDL_USE_ONE_THREAD_PER_DISPLAY if (pj_list_empty(&strm->sf->streams)) pj_sem_post(strm->sf->sem); -#endif /* !SDL_USE_ONE_THREAD_PER_DISPLAY */ pj_list_insert_after(&strm->sf->streams, &strm->list_entry); pj_mutex_unlock(strm->sf->mutex); - -#if SDL_USE_ONE_THREAD_PER_DISPLAY - status = pj_thread_create(pool, "sdl_thread", sdl_thread, - &sdl_dev, 0, 0, &strm->sdl_thread); - if (status != PJ_SUCCESS) { - goto on_error; - } -#endif /* SDL_USE_ONE_THREAD_PER_DISPLAY */ - - while(strm->status == PJ_SUCCESS && !strm->surf && !strm->overlay -#if SDL_VERSION_ATLEAST(1,3,0) - && !strm->scr_tex -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ -#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL - && !strm->texture -#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ - ) - { - pj_thread_sleep(10); - } - if ((status = strm->status) != PJ_SUCCESS) { - goto on_error; - } } /* Apply the remaining settings */ @@ -1173,11 +918,6 @@ static pj_status_t sdl_factory_create_stream( PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION, ¶m->window_pos); } - if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE) { - sdl_stream_set_cap(&strm->base, - PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE, - ¶m->window_hide); - } /* Done */ strm->base.op = &stream_op; @@ -1224,18 +964,22 @@ static pj_status_t sdl_stream_get_param(pjmedia_vid_dev_stream *s, return PJ_SUCCESS; } -/* API: get capability */ -static pj_status_t sdl_stream_get_cap(pjmedia_vid_dev_stream *s, - pjmedia_vid_dev_cap cap, - void *pval) -{ - struct sdl_stream *strm = (struct sdl_stream*)s; - - PJ_UNUSED_ARG(strm); +struct strm_cap { + struct sdl_stream *strm; + pjmedia_vid_dev_cap cap; + union { + void *pval; + const void *cpval; + } pval; +}; - PJ_ASSERT_RETURN(s && pval, PJ_EINVAL); +static pj_status_t get_cap(void *data) +{ + struct strm_cap *scap = (struct strm_cap *)data; + struct sdl_stream *strm = scap->strm; + pjmedia_vid_dev_cap cap = scap->cap; + void *pval = scap->pval.pval; -#if SDL_VERSION_ATLEAST(1,3,0) if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) { SDL_SysWMinfo info; @@ -1243,24 +987,31 @@ static pj_status_t sdl_stream_get_cap(pjmedia_vid_dev_stream *s, if (SDL_GetWindowWMInfo(strm->window, &info)) { pjmedia_vid_dev_hwnd *wnd = (pjmedia_vid_dev_hwnd *)pval; - if (info.subsystem == SDL_SYSWM_WINDOWS) { + if (0) { } #if defined(SDL_VIDEO_DRIVER_WINDOWS) + else if (info.subsystem == SDL_SYSWM_WINDOWS) { wnd->type = PJMEDIA_VID_DEV_HWND_TYPE_WINDOWS; wnd->info.win.hwnd = (void *)info.info.win.window; + } #endif - } else if (info.subsystem == SDL_SYSWM_X11) { #if defined(SDL_VIDEO_DRIVER_X11) + else if (info.subsystem == SDL_SYSWM_X11) { wnd->info.x11.window = (void *)info.info.x11.window; wnd->info.x11.display = (void *)info.info.x11.display; + } #endif - } else if (info.subsystem == SDL_SYSWM_COCOA) { #if defined(SDL_VIDEO_DRIVER_COCOA) + else if (info.subsystem == SDL_SYSWM_COCOA) { wnd->info.cocoa.window = (void *)info.info.cocoa.window; + } #endif - } else if (info.subsystem == SDL_SYSWM_UIKIT) { #if defined(SDL_VIDEO_DRIVER_UIKIT) + else if (info.subsystem == SDL_SYSWM_UIKIT) { wnd->info.ios.window = (void *)info.info.uikit.window; + } #endif + else { + return PJMEDIA_EVID_INVCAP; } return PJ_SUCCESS; } else @@ -1278,25 +1029,37 @@ static pj_status_t sdl_stream_get_cap(pjmedia_vid_dev_stream *s, *((pj_bool_t *)pval) = (flag | SDL_WINDOW_HIDDEN)? PJ_TRUE: PJ_FALSE; return PJ_SUCCESS; } -#else /* SDL_VERSION_ATLEAST(1,3,0) */ - PJ_UNUSED_ARG(cap); -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ return PJMEDIA_EVID_INVCAP; } -/* API: set capability */ -static pj_status_t sdl_stream_set_cap(pjmedia_vid_dev_stream *s, +/* API: get capability */ +static pj_status_t sdl_stream_get_cap(pjmedia_vid_dev_stream *s, pjmedia_vid_dev_cap cap, - const void *pval) + void *pval) { struct sdl_stream *strm = (struct sdl_stream*)s; - - PJ_UNUSED_ARG(strm); + struct strm_cap scap; + pj_status_t status; PJ_ASSERT_RETURN(s && pval, PJ_EINVAL); -#if SDL_VERSION_ATLEAST(1,3,0) + scap.strm = strm; + scap.cap = cap; + scap.pval.pval = pval; + + job_queue_post_job(strm->sf->jq, get_cap, &scap, 0, &status); + + return status; +} + +static pj_status_t set_cap(void *data) +{ + struct strm_cap *scap = (struct strm_cap *)data; + struct sdl_stream *strm = scap->strm; + pjmedia_vid_dev_cap cap = scap->cap; + const void *pval = scap->pval.cpval; + if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION) { SDL_SetWindowPosition(strm->window, ((pjmedia_coord *)pval)->x, ((pjmedia_coord *)pval)->y); @@ -1307,47 +1070,58 @@ static pj_status_t sdl_stream_set_cap(pjmedia_vid_dev_stream *s, else SDL_ShowWindow(strm->window); return PJ_SUCCESS; - } else -#endif /* SDL_VERSION_ATLEAST(1,3,0) */ - if (cap == PJMEDIA_VID_DEV_CAP_FORMAT) { - strm->new_fmt = (pjmedia_format *)pval; - while (strm->new_fmt) - pj_thread_sleep(10); - - if (strm->status != PJ_SUCCESS) { - pj_status_t status = strm->status; + } else if (cap == PJMEDIA_VID_DEV_CAP_FORMAT) { + pj_status_t status; + + status = change_format(strm, (pjmedia_format *)pval); + if (status != PJ_SUCCESS) { + pj_status_t status_; /** * Failed to change the output format. Try to revert * to its original format. */ - strm->new_fmt = &strm->param.fmt; - while (strm->new_fmt) - pj_thread_sleep(10); - - if (strm->status != PJ_SUCCESS) { + status_ = change_format(strm, &strm->param.fmt); + if (status_ != PJ_SUCCESS) { /** * This means that we failed to revert to our * original state! */ status = PJMEDIA_EVID_ERR; } - - strm->status = status; } - return strm->status; + return status; } else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE) { - strm->new_disp_size = (pjmedia_rect_size *)pval; - while (strm->new_disp_size) - pj_thread_sleep(10); - - return strm->status; + pjmedia_rect_size *new_size = (pjmedia_rect_size *)pval; + + SDL_SetWindowSize(strm->window, new_size->w, new_size->h); + return resize_disp(strm, new_size); } return PJMEDIA_EVID_INVCAP; } +/* API: set capability */ +static pj_status_t sdl_stream_set_cap(pjmedia_vid_dev_stream *s, + pjmedia_vid_dev_cap cap, + const void *pval) +{ + struct sdl_stream *strm = (struct sdl_stream*)s; + struct strm_cap scap; + pj_status_t status; + + PJ_ASSERT_RETURN(s && pval, PJ_EINVAL); + + scap.strm = strm; + scap.cap = cap; + scap.pval.cpval = pval; + + job_queue_post_job(strm->sf->jq, set_cap, &scap, 0, &status); + + return status; +} + /* API: Start stream. */ static pj_status_t sdl_stream_start(pjmedia_vid_dev_stream *strm) { @@ -1356,23 +1130,19 @@ static pj_status_t sdl_stream_start(pjmedia_vid_dev_stream *strm) PJ_LOG(4, (THIS_FILE, "Starting sdl video stream")); stream->is_running = PJ_TRUE; - stream->render_exited = PJ_FALSE; return PJ_SUCCESS; } + /* API: Stop stream. */ static pj_status_t sdl_stream_stop(pjmedia_vid_dev_stream *strm) { struct sdl_stream *stream = (struct sdl_stream*)strm; - unsigned i; PJ_LOG(4, (THIS_FILE, "Stopping sdl video stream")); - /* Wait for renderer put_frame() to finish */ stream->is_running = PJ_FALSE; - for (i=0; !stream->render_exited && i<50; ++i) - pj_thread_sleep(10); return PJ_SUCCESS; } @@ -1382,19 +1152,15 @@ static pj_status_t sdl_stream_stop(pjmedia_vid_dev_stream *strm) static pj_status_t sdl_stream_destroy(pjmedia_vid_dev_stream *strm) { struct sdl_stream *stream = (struct sdl_stream*)strm; + pj_status_t status; PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); sdl_stream_stop(strm); - if (!stream->is_quitting) { - stream->is_quitting = PJ_TRUE; - if (stream->sdl_thread) - pj_thread_join(stream->sdl_thread); - while (!stream->is_destroyed) { - pj_thread_sleep(10); - } - } + job_queue_post_job(stream->sf->jq, sdl_destroy_all, strm, 0, &status); + if (status != PJ_SUCCESS) + return status; pj_mutex_lock(stream->sf->mutex); if (!pj_list_empty(&stream->list_entry)) @@ -1406,49 +1172,133 @@ static pj_status_t sdl_stream_destroy(pjmedia_vid_dev_stream *strm) return PJ_SUCCESS; } -#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 -@implementation SDLDelegate -- (void)sdl_init +/**************************************************************************** + * Job queue implementation + */ +static int job_thread(void * data) { - if (SDL_Init(SDL_INIT_VIDEO)) { - PJ_LOG(4, (THIS_FILE, "Cannot initialize SDL")); - status = PJMEDIA_EVID_INIT; + job_queue *jq = (job_queue *)data; + + while (1) { + job *jb; + + /* Wait until there is a job. */ + pj_sem_wait(jq->sem); + + /* Make sure there is no pending jobs before we quit. */ + if (jq->is_quitting && jq->head == jq->tail && !jq->is_full) + break; + + jb = jq->jobs[jq->head]; + jb->retval = (*jb->func)(jb->data); + pj_sem_post(jq->job_sem[jq->head]); + pj_mutex_lock(jq->mutex); + jq->head = (jq->head + 1) % MAX_JOBS; + jq->is_full = PJ_FALSE; + pj_mutex_unlock(jq->mutex); } - status = PJ_SUCCESS; -} -- (void)sdl_quit -{ - SDL_Quit(); + return 0; } -- (void)detect_fmt_change +static pj_status_t job_queue_create(pj_pool_t *pool, job_queue **pjq) { - detect_fmt_change(strm); -} + unsigned i; + pj_status_t status; -- (void)sdl_create -{ - sdl_create(strm); -} + job_queue *jq = PJ_POOL_ZALLOC_T(pool, job_queue); + pj_sem_create(pool, "thread_sem", 0, MAX_JOBS + 1, &jq->sem); -- (void)sdl_destroy -{ - sdl_destroy(strm, PJ_TRUE); +#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 + PJ_UNUSED_ARG(status); +#else + status = pj_thread_create(pool, "job_th", job_thread, jq, 0, 0, + &jq->thread); + if (status != PJ_SUCCESS) { + job_queue_destroy(jq); + return status; + } +#endif /* PJ_DARWINOS */ + + for (i = 0; i < MAX_JOBS; i++) { + pj_sem_create(pool, "job_sem", 0, 1, &jq->job_sem[i]); + } + pj_mutex_create_recursive(pool, "job_mutex", &jq->mutex); + + *pjq = jq; + return PJ_SUCCESS; } -- (void)handle_event +static pj_status_t job_queue_post_job(job_queue *jq, job_func_ptr func, + void *data, unsigned flags, + pj_status_t *retval) { - strm = handle_event(sf, strm, &ev_type); + job jb; + int tail; + + if (jq->is_quitting) + return PJ_EBUSY; + + jb.func = func; + jb.data = data; + jb.flags = flags; + +#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 + PJ_UNUSED_ARG(tail); + NSAutoreleasePool *apool = [[NSAutoreleasePool alloc]init]; + JQDelegate *jqd = [[JQDelegate alloc]init]; + jqd->pjob = &jb; + [jqd performSelectorOnMainThread:@selector(run_job) + withObject:nil waitUntilDone:YES]; + [jqd release]; + [apool release]; +#else /* PJ_DARWINOS */ + pj_mutex_lock(jq->mutex); + if (jq->is_full) { + /* Sorry, the queue is full! */ + pj_mutex_unlock(jq->mutex); + *retval = PJ_ETOOMANY; + return PJ_ETOOMANY; + } + jq->jobs[jq->tail] = &jb; + tail = jq->tail; + jq->tail = (jq->tail + 1) % MAX_JOBS; + if (jq->tail == jq->head) + jq->is_full = PJ_TRUE; + pj_mutex_unlock(jq->mutex); + + pj_sem_post(jq->sem); + /* Wait until our posted job is completed. */ + pj_sem_wait(jq->job_sem[tail]); +#endif /* PJ_DARWINOS */ + + *retval = jb.retval; + + return PJ_SUCCESS; } -- (void)put_frame +static pj_status_t job_queue_destroy(job_queue *jq) { - put_frame(strm, &strm->frame); -} + unsigned i; -@end -#endif /* PJ_DARWINOS */ + jq->is_quitting = PJ_TRUE; + + if (jq->thread) { + pj_sem_post(jq->sem); + pj_thread_join(jq->thread); + } + + if (jq->sem) { + pj_sem_destroy(jq->sem); + jq->sem = NULL; + } + for (i = 0; i < MAX_JOBS; i++) { + pj_sem_destroy(jq->job_sem[i]); + } + pj_mutex_destroy(jq->mutex); + + return PJ_SUCCESS; +} #ifdef _MSC_VER # pragma comment( lib, "sdl.lib") -- cgit v1.2.3