Changeset 3689 for pjproject


Ignore:
Timestamp:
Aug 8, 2011 5:41:19 AM (13 years ago)
Author:
ming
Message:

Re #1334: support for various thread models for SDL 1.3. There are three thread models implemented: running SDL on the main thread (by default it will be used on Mac/iOS), running SDL in ONE thread (by default it will be used on Linux), or running SDL in a single thread for each window (by default it will be used on Windows).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia-videodev/sdl_dev.c

    r3676 r3689  
    2828#   include "TargetConditionals.h" 
    2929#   include <Foundation/Foundation.h> 
    30 #endif /* PJ_DARWINOS */ 
     30#   define SDL_USE_ONE_THREAD_PER_DISPLAY 1 
     31#elif defined(PJ_WIN32) && PJ_WIN32 != 0  
     32#   define SDL_USE_ONE_THREAD_PER_DISPLAY 1 
     33#else 
     34#   define SDL_USE_ONE_THREAD_PER_DISPLAY 0 
     35#endif 
    3136 
    3237#include <SDL.h> 
     
    3540#   include "SDL_opengl.h" 
    3641#   define OPENGL_DEV_IDX 1 
    37 #else /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 
    38 #   define OPENGL_DEV_IDX -999 
    3942#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 
    4043 
     
    100103    @public 
    101104    struct sdl_stream       *strm; 
     105    struct sdl_factory      *sf; 
     106    pjmedia_event_type       ev_type; 
     107    pj_status_t              status; 
    102108} 
    103109 
     
    118124}; 
    119125 
     126/* Linked list of streams */ 
     127struct stream_list 
     128{ 
     129    PJ_DECL_LIST_MEMBER(struct stream_list); 
     130    struct sdl_stream   *stream; 
     131}; 
     132 
    120133/* sdl_ factory */ 
    121134struct sdl_factory 
     
    127140    unsigned                     dev_count; 
    128141    struct sdl_dev_info         *dev_info; 
    129 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    130     NSAutoreleasePool           *apool; 
    131     SDLDelegate                 *delegate; 
    132 #endif /* PJ_DARWINOS */ 
     142 
     143    pj_thread_t                 *sdl_thread;        /**< SDL thread.        */ 
     144    pj_status_t                  status; 
     145    pj_sem_t                    *sem; 
     146    pj_mutex_t                  *mutex; 
     147    struct stream_list           streams; 
     148    pj_bool_t                    is_quitting; 
    133149}; 
    134150 
     
    144160 
    145161    pj_thread_t                 *sdl_thread;        /**< SDL thread.        */ 
     162    pj_bool_t                    is_initialized; 
    146163    pj_bool_t                    is_quitting; 
     164    pj_bool_t                    is_destroyed; 
    147165    pj_bool_t                    is_running; 
    148166    pj_bool_t                    render_exited; 
     
    151169    pjmedia_rect_size           *new_disp_size; 
    152170    pj_timestamp                 last_ts; 
     171    pjmedia_frame                frame; 
     172    pj_size_t                    frame_buf_size; 
     173    struct stream_list           list_entry; 
     174    struct sdl_factory          *sf; 
    153175 
    154176#if SDL_VERSION_ATLEAST(1,3,0) 
     
    169191    GLuint                       texture; 
    170192#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 
    171     void                        *tex_buf; 
    172     pj_size_t                    tex_buf_size; 
    173  
    174 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    175     NSAutoreleasePool           *apool; 
    176     SDLDelegate                 *delegate; 
    177     const pjmedia_frame         *frame; 
    178 #endif /* PJ_DARWINOS */ 
    179  
    180     /* For frame conversion */ 
    181     pjmedia_converter           *conv; 
    182     pjmedia_conversion_param     conv_param; 
    183     pjmedia_frame                conv_buf; 
    184193 
    185194    pjmedia_video_apply_fmt_param vafp; 
    186195}; 
    187196 
     197struct sdl_dev_t 
     198{ 
     199    struct sdl_factory *sf; 
     200    struct sdl_stream  *strm; 
     201}; 
    188202 
    189203/* Prototypes */ 
     
    220234static pj_status_t sdl_stream_destroy(pjmedia_vid_dev_stream *strm); 
    221235 
     236static int sdl_thread(void * data); 
     237 
    222238/* Operations */ 
    223239static pjmedia_vid_dev_factory_op factory_op = 
     
    265281} 
    266282 
    267  
    268283/* API: init factory */ 
    269284static pj_status_t sdl_factory_init(pjmedia_vid_dev_factory *f) 
     
    272287    struct sdl_dev_info *ddi; 
    273288    unsigned i, j; 
     289    struct sdl_dev_t sdl_dev; 
     290    pj_status_t status; 
    274291    SDL_version version; 
    275     SDL_VERSION(&version); 
    276  
    277 #if SDL_VERSION_ATLEAST(1,3,0) 
    278 #   if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    279     sf->apool = [[NSAutoreleasePool alloc] init]; 
    280     sf->delegate = [[SDLDelegate alloc] init]; 
    281     [sf->delegate performSelectorOnMainThread:@selector(sdl_init)  
    282                   withObject:nil waitUntilDone:YES]; 
    283 #   else /* PJ_DARWINOS */ 
    284     /* Initialize the SDL library */ 
    285     if (SDL_Init(SDL_INIT_VIDEO)) 
     292 
     293    pj_list_init(&sf->streams); 
     294    status = pj_mutex_create_recursive(sf->pool, "sdl_factory", 
     295                                       &sf->mutex); 
     296    if (status != PJ_SUCCESS) 
     297        return status; 
     298 
     299    status = pj_sem_create(sf->pool, NULL, 0, 1, &sf->sem); 
     300    if (status != PJ_SUCCESS) 
     301        return status; 
     302 
     303    sf->status = PJ_EUNKNOWN; 
     304    sdl_dev.sf = sf; 
     305    sdl_dev.strm = NULL; 
     306    status = pj_thread_create(sf->pool, "sdl_thread", sdl_thread, 
     307                              &sdl_dev, 0, 0, &sf->sdl_thread); 
     308    if (status != PJ_SUCCESS) { 
    286309        return PJMEDIA_EVID_INIT; 
    287 #   endif /* PJ_DARWINOS */ 
    288 #endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
     310    } 
     311 
     312    while (sf->status == PJ_EUNKNOWN) 
     313        pj_thread_sleep(10); 
     314 
     315    if (sf->status != PJ_SUCCESS) 
     316        return sf->status; 
    289317 
    290318    sf->dev_count = 1; 
     
    330358    } 
    331359 
     360    SDL_VERSION(&version); 
    332361    PJ_LOG(4, (THIS_FILE, "SDL %d.%d initialized", 
    333362                          version.major, version.minor)); 
     
    342371    pj_pool_t *pool = sf->pool; 
    343372 
     373    pj_assert(pj_list_empty(&sf->streams)); 
     374 
     375    sf->is_quitting = PJ_TRUE; 
     376    if (sf->sdl_thread) { 
     377        pj_sem_post(sf->sem); 
     378        pj_thread_join(sf->sdl_thread); 
     379    } 
     380 
     381    if (sf->mutex) { 
     382        pj_mutex_destroy(sf->mutex); 
     383        sf->mutex = NULL; 
     384    } 
     385 
     386    if (sf->sem) { 
     387        pj_sem_destroy(sf->sem); 
     388        sf->sem = NULL; 
     389    } 
     390 
    344391    sf->pool = NULL; 
    345392    pj_pool_release(pool); 
    346  
    347 #if SDL_VERSION_ATLEAST(1,3,0) 
    348 #   if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    349     [sf->delegate performSelectorOnMainThread:@selector(sdl_quit)  
    350                   withObject:nil waitUntilDone:YES]; 
    351     [sf->delegate release]; 
    352     [sf->apool release]; 
    353 #   else /* PJ_DARWINOS */ 
    354     SDL_Quit(); 
    355 #   endif /* PJ_DARWINOS */ 
    356 #endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
    357393 
    358394    return PJ_SUCCESS; 
     
    507543        Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; 
    508544 
     545#   if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 
    509546        if (strm->param.rend_id == OPENGL_DEV_IDX) 
    510547            flags |= SDL_WINDOW_OPENGL; 
     548#   endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 
    511549 
    512550        if (strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) { 
     
    588626        if (!strm->texture) 
    589627            return PJMEDIA_EVID_SYSERR; 
    590  
    591 #   if !defined(PJ_DARWINOS) || PJ_DARWINOS == 0 
    592         /** 
    593          * OpenGL drawing must be in the same 
    594          * thread that calls SDL_SetVideoMode(), hence we need a buffer 
    595          * for the frame from sdl_stream_put_frame() 
    596          */ 
    597         if (strm->vafp.framebytes > strm->tex_buf_size) { 
    598             strm->tex_buf_size = strm->vafp.framebytes; 
    599             strm->tex_buf = pj_pool_alloc(strm->pool, strm->vafp.framebytes); 
    600         } 
    601 #   endif /* PJ_DARWINOS */ 
    602628    } else 
    603629#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 
     
    611637     
    612638        strm->pitch = strm->rect.w * SDL_BYTESPERPIXEL(sdl_info->sdl_format); 
    613  
    614 #   if !defined(PJ_DARWINOS) || PJ_DARWINOS == 0 
    615         if (strm->vafp.framebytes > strm->tex_buf_size) { 
    616             strm->tex_buf_size = strm->vafp.framebytes; 
    617             strm->tex_buf = pj_pool_alloc(strm->pool, strm->vafp.framebytes); 
    618         } 
    619 #   endif /* !PJ_DARWINOS */ 
    620639    } 
    621640#else /* SDL_VERSION_ATLEAST(1,3,0) */ 
     
    639658#endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
    640659 
     660    if (strm->vafp.framebytes > strm->frame_buf_size) { 
     661        strm->frame_buf_size = strm->vafp.framebytes; 
     662        strm->frame.buf = pj_pool_alloc(strm->pool, strm->vafp.framebytes); 
     663    } 
     664 
    641665    return PJ_SUCCESS; 
    642666} 
     
    644668static pj_status_t sdl_create(struct sdl_stream *strm) 
    645669{ 
     670    strm->is_initialized = PJ_TRUE; 
     671 
    646672#if !(SDL_VERSION_ATLEAST(1,3,0)) 
    647673    if (SDL_Init(SDL_INIT_VIDEO)) { 
    648674        strm->status = PJMEDIA_EVID_INIT; 
    649         goto on_return; 
     675        return strm->status; 
    650676    } 
    651677#endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */ 
     
    658684 
    659685    strm->status = sdl_create_view(strm, &strm->param.fmt); 
    660     if (strm->status != PJ_SUCCESS) 
    661         goto on_return; 
    662  
    663 on_return: 
    664     if (strm->status != PJ_SUCCESS) { 
    665         sdl_destroy(strm, PJ_TRUE); 
    666 #if !(SDL_VERSION_ATLEAST(1,3,0)) 
    667         SDL_Quit(); 
    668 #endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */ 
    669         strm->screen = NULL; 
    670     } 
    671      
    672686    return strm->status; 
    673687} 
     
    675689static void detect_fmt_change(struct sdl_stream *strm) 
    676690{ 
     691    strm->status = PJ_SUCCESS; 
    677692    if (strm->new_fmt || strm->new_disp_size) { 
    678         /* Stop the stream */ 
    679         sdl_stream_stop((pjmedia_vid_dev_stream *)strm); 
    680  
    681693        if (strm->new_disp_size) 
    682694            pj_memcpy(&strm->param.disp_size, strm->new_disp_size, 
     
    690702            if (strm->new_fmt) 
    691703                pjmedia_format_copy(&strm->param.fmt, strm->new_fmt); 
    692             /* Restart the stream */ 
    693             sdl_stream_start((pjmedia_vid_dev_stream *)strm); 
    694704        } 
    695705        strm->new_fmt = NULL; 
     
    698708} 
    699709 
     710static pj_status_t put_frame(struct sdl_stream *stream, 
     711                             const pjmedia_frame *frame) 
     712{ 
     713    if (!stream->is_running) 
     714        return PJ_SUCCESS; 
     715 
     716    if (stream->surf) { 
     717        if (SDL_MUSTLOCK(stream->surf)) { 
     718            if (SDL_LockSurface(stream->surf) < 0) { 
     719                PJ_LOG(3, (THIS_FILE, "Unable to lock SDL surface")); 
     720                return PJMEDIA_EVID_NOTREADY; 
     721            } 
     722        } 
     723         
     724        pj_memcpy(stream->surf->pixels, frame->buf, 
     725                  stream->vafp.framebytes); 
     726         
     727        if (SDL_MUSTLOCK(stream->surf)) { 
     728            SDL_UnlockSurface(stream->surf); 
     729        } 
     730#if SDL_VERSION_ATLEAST(1,3,0) 
     731        SDL_UpdateWindowSurface(stream->window); 
     732#else /* SDL_VERSION_ATLEAST(1,3,0) */ 
     733        SDL_BlitSurface(stream->surf, NULL, stream->screen, &stream->dstrect); 
     734#endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
     735    } else if (stream->overlay) { 
     736        int i, sz, offset; 
     737         
     738        if (SDL_LockYUVOverlay(stream->overlay) < 0) { 
     739            PJ_LOG(3, (THIS_FILE, "Unable to lock SDL overlay")); 
     740            return PJMEDIA_EVID_NOTREADY; 
     741        } 
     742         
     743        for (i = 0, offset = 0; i < stream->overlay->planes; i++) { 
     744            sz = stream->vafp.plane_bytes[i]; 
     745            pj_memcpy(stream->overlay->pixels[i], 
     746                      (char *)frame->buf + offset, sz); 
     747            offset += sz; 
     748        } 
     749         
     750        SDL_UnlockYUVOverlay(stream->overlay); 
     751        SDL_DisplayYUVOverlay(stream->overlay, &stream->dstrect); 
     752    } 
     753#if SDL_VERSION_ATLEAST(1,3,0) 
     754    else if (stream->scr_tex) { 
     755        SDL_UpdateTexture(stream->scr_tex, NULL, frame->buf, stream->pitch); 
     756        SDL_RenderClear(stream->renderer); 
     757        SDL_RenderCopy(stream->renderer, stream->scr_tex, NULL, NULL); 
     758        SDL_RenderPresent(stream->renderer); 
     759    } 
     760#endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
    700761#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 
    701 static void draw_gl(struct sdl_stream *stream, void *tex_buf) 
    702 { 
    703     if (stream->texture) { 
     762    else if (stream->param.rend_id == OPENGL_DEV_IDX && stream->texture) { 
    704763        glBindTexture(GL_TEXTURE_2D, stream->texture); 
    705764        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
     
    707766        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 
    708767                     stream->rect.w, stream->rect.h, 0, 
    709                      GL_RGBA, GL_UNSIGNED_BYTE, tex_buf); 
     768                     GL_RGBA, GL_UNSIGNED_BYTE, frame->buf); 
    710769        glBegin(GL_TRIANGLE_STRIP); 
    711770        glTexCoord2f(0, 0); glVertex2i(0, 0); 
     
    721780#   endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
    722781    } 
    723 } 
    724782#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 
    725783 
    726 static void draw_texture(struct sdl_stream *stream, void *tex_buf) 
    727 { 
     784    return PJ_SUCCESS; 
     785} 
     786 
     787static struct sdl_stream* find_stream(struct sdl_factory *sf, 
     788                                      Uint32 windowID, 
     789                                      pjmedia_event *pevent) 
     790{ 
     791    struct stream_list *it, *itBegin; 
     792    struct sdl_stream *strm = NULL; 
     793 
     794    itBegin = &sf->streams; 
     795    for (it = itBegin->next; it != itBegin; it = it->next) { 
    728796#if SDL_VERSION_ATLEAST(1,3,0) 
    729     SDL_UpdateTexture(stream->scr_tex, NULL, tex_buf, stream->pitch); 
    730     SDL_RenderClear(stream->renderer); 
    731     SDL_RenderCopy(stream->renderer, stream->scr_tex, NULL, NULL); 
    732     SDL_RenderPresent(stream->renderer); 
     797        if (SDL_GetWindowID(it->stream->window) == windowID) 
    733798#else /* SDL_VERSION_ATLEAST(1,3,0) */ 
    734     PJ_UNUSED_ARG(stream); 
    735     PJ_UNUSED_ARG(tex_buf); 
     799        PJ_UNUSED_ARG(windowID); 
    736800#endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
    737 } 
    738  
    739 static void handle_event(struct sdl_stream *strm) 
    740 { 
    741     const pjmedia_video_format_info *vfi; 
    742     pjmedia_video_format_detail *vfd; 
    743     pj_bool_t notify_wnd_closed_event = PJ_FALSE; 
     801        { 
     802            strm = it->stream; 
     803            break; 
     804        } 
     805    } 
     806  
     807    if (strm) 
     808        pjmedia_event_init(pevent, PJMEDIA_EVENT_NONE, &strm->last_ts, 
     809                           &strm->base.epub); 
     810 
     811    return strm; 
     812} 
     813 
     814static int poll_event(struct sdl_factory *sf, pjmedia_event *pevent, 
     815                      struct sdl_stream **strm) 
     816{ 
     817    int retval; 
    744818    SDL_Event sevent; 
    745     pjmedia_event pevent; 
    746      
    747     vfi = pjmedia_get_video_format_info(pjmedia_video_format_mgr_instance(), 
    748                                         strm->param.fmt.id); 
    749     vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, PJ_TRUE); 
    750  
    751     if (strm->tex_buf) { 
    752 #if SDL_VERSION_ATLEAST(1,3,0) 
    753         if (strm->scr_tex) { 
    754             draw_texture(strm, strm->tex_buf); 
    755         } 
    756 #else /* SDL_VERSION_ATLEAST(1,3,0) */ 
    757         if (0) { } 
    758 #endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
    759 #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 
    760         else if (strm->param.rend_id == OPENGL_DEV_IDX) { 
    761             draw_gl(strm, strm->tex_buf); 
    762         } 
    763 #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 
    764     } 
    765  
    766     detect_fmt_change(strm); 
    767  
    768     /** 
    769      * The event polling must be placed in the same thread that 
    770      * call SDL_SetVideoMode(). Please consult the official doc of 
    771      * SDL_PumpEvents(). 
    772      */ 
    773     while (SDL_PollEvent(&sevent)) { 
    774         pjmedia_event_init(&pevent, PJMEDIA_EVENT_NONE, &strm->last_ts, 
    775                            &strm->base.epub); 
     819 
     820    retval = SDL_PollEvent(&sevent); 
     821    if (retval) { 
     822#if !(SDL_VERSION_ATLEAST(1,3,0)) 
     823        *strm = find_stream(sf, 0, pevent); 
     824        pj_assert(strm); 
     825#endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */ 
    776826 
    777827        switch(sevent.type) { 
    778828            case SDL_MOUSEBUTTONDOWN: 
    779                 pevent.type = PJMEDIA_EVENT_MOUSE_BTN_DOWN; 
     829#if SDL_VERSION_ATLEAST(1,3,0) 
     830                *strm = find_stream(sf, sevent.button.windowID, pevent); 
     831#endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
     832                pevent->type = PJMEDIA_EVENT_MOUSE_BTN_DOWN; 
    780833                break; 
    781834#if SDL_VERSION_ATLEAST(1,3,0) 
    782835            case SDL_WINDOWEVENT: 
     836                *strm = find_stream(sf, sevent.window.windowID, pevent); 
    783837                switch (sevent.window.event) { 
    784838                    case SDL_WINDOWEVENT_RESIZED: 
    785                         pevent.type = PJMEDIA_EVENT_WND_RESIZED; 
    786                         pevent.data.wnd_resized.new_size.w = 
     839                        pevent->type = PJMEDIA_EVENT_WND_RESIZED; 
     840                        pevent->data.wnd_resized.new_size.w = 
    787841                            sevent.window.data1; 
    788                         pevent.data.wnd_resized.new_size.h = 
     842                        pevent->data.wnd_resized.new_size.h = 
    789843                            sevent.window.data2; 
    790844                        break; 
     845                    case SDL_WINDOWEVENT_CLOSE: 
     846                        pevent->type = PJMEDIA_EVENT_WND_CLOSING; 
     847                        break; 
    791848                } 
    792849                break; 
    793850#else /* SDL_VERSION_ATLEAST(1,3,0) */ 
    794851            case SDL_VIDEORESIZE: 
    795                 pevent.type = PJMEDIA_EVENT_WND_RESIZED; 
    796                 pevent.data.wnd_resized.new_size.w = sevent.resize.w; 
    797                 pevent.data.wnd_resized.new_size.h = sevent.resize.h; 
     852                pevent->type = PJMEDIA_EVENT_WND_RESIZED; 
     853                pevent->data.wnd_resized.new_size.w = sevent.resize.w; 
     854                pevent->data.wnd_resized.new_size.h = sevent.resize.h; 
    798855                break; 
    799856            case SDL_QUIT: 
    800                 pevent.type = PJMEDIA_EVENT_WND_CLOSING; 
     857                pevent->type = PJMEDIA_EVENT_WND_CLOSING; 
    801858                break; 
    802859#endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
    803860        } 
    804  
    805         if (pevent.type != PJMEDIA_EVENT_NONE) { 
    806             pj_status_t status; 
    807  
    808             status = pjmedia_event_publish(&strm->base.epub, &pevent); 
     861    } 
     862 
     863    return retval; 
     864} 
     865 
     866static struct sdl_stream* handle_event(struct sdl_factory *sf, 
     867                                       struct sdl_stream *rcv_strm, 
     868                                       pjmedia_event_type *ev_type) 
     869{ 
     870    struct sdl_stream *strm = NULL; 
     871    pjmedia_event pevent; 
     872 
     873    *ev_type = PJMEDIA_EVENT_NONE; 
     874    while (poll_event(sf, &pevent, &strm)) { 
     875        *ev_type = pevent.type; 
     876        if (pevent.type != PJMEDIA_EVENT_NONE && strm && 
     877            (!rcv_strm || rcv_strm == strm)) 
     878        { 
     879            pjmedia_event_publish(&strm->base.epub, &pevent); 
    809880 
    810881            switch (pevent.type) { 
    811882            case PJMEDIA_EVENT_WND_RESIZED: 
    812883                strm->new_disp_size = &pevent.data.wnd_resized.new_size; 
     884                strm->status = PJ_SUCCESS; 
    813885                detect_fmt_change(strm); 
     886                if (strm->status != PJ_SUCCESS) 
     887                    return strm; 
    814888                break; 
    815889 
     
    825899                 */ 
    826900                strm->is_quitting = PJ_TRUE; 
    827                 notify_wnd_closed_event = PJ_TRUE; 
    828901                sdl_stream_stop(&strm->base); 
    829                 goto on_return; 
    830  
     902 
     903                return strm; 
    831904            default: 
    832905                /* Just to prevent gcc warning about unused enums */ 
     
    836909    } 
    837910 
    838     return; 
    839  
    840 on_return: 
    841     sdl_destroy(strm, PJ_TRUE); 
    842 #if !(SDL_VERSION_ATLEAST(1,3,0)) 
    843     SDL_Quit(); 
    844 #endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */ 
    845     strm->screen = NULL; 
    846  
    847     if (notify_wnd_closed_event) { 
    848         pjmedia_event pevent; 
    849  
    850         pjmedia_event_init(&pevent, PJMEDIA_EVENT_WND_CLOSED, &strm->last_ts, 
    851                            &strm->base.epub); 
    852         pjmedia_event_publish(&strm->base.epub, &pevent); 
    853     } 
    854  
    855     /* 
    856      * Note: don't access the stream after this point, it  might have 
    857      * been destroyed 
    858      */ 
     911    return strm; 
    859912} 
    860913 
    861914static int sdl_thread(void * data) 
    862915{ 
    863     struct sdl_stream *strm = (struct sdl_stream*)data; 
     916    struct sdl_dev_t *sdl_dev = (struct sdl_dev_t *)data; 
     917    struct sdl_factory *sf = sdl_dev->sf; 
     918    struct sdl_stream *strm = sdl_dev->strm; 
    864919 
    865920#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    866     while(!strm->is_quitting) { 
    867         [strm->delegate performSelectorOnMainThread:@selector(handle_event) 
    868                         withObject:nil waitUntilDone:YES]; 
    869     } 
    870     [strm->delegate performSelectorOnMainThread:@selector(sdl_destroy) 
    871                     withObject:nil waitUntilDone:YES]; 
     921    NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init]; 
     922    SDLDelegate *delegate = [[SDLDelegate alloc] init]; 
     923#endif /* PJ_DARWINOS */ 
     924 
     925#if SDL_VERSION_ATLEAST(1,3,0) 
     926#   if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
     927    [delegate performSelectorOnMainThread:@selector(sdl_init)  
     928              withObject:nil waitUntilDone:YES]; 
     929    if (delegate->status != PJ_SUCCESS) 
     930        goto on_error; 
     931#   else /* PJ_DARWINOS */ 
     932    /* Initialize the SDL library */ 
     933    if (SDL_Init(SDL_INIT_VIDEO)) { 
     934        sf->status = PJMEDIA_EVID_INIT; 
     935        goto on_error; 
     936    } 
     937#   endif /* PJ_DARWINOS */ 
     938#endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
     939    sf->status = PJ_SUCCESS; 
     940 
     941    while (!sf->is_quitting) { 
     942        struct stream_list *it, *itBegin; 
     943        pjmedia_event_type ev_type; 
     944        struct sdl_stream *ev_stream; 
     945 
     946        pj_mutex_lock(sf->mutex); 
     947 
     948        if (!strm && pj_list_empty(&sf->streams)) { 
     949            /* Wait until there is any stream. */ 
     950            pj_mutex_unlock(sf->mutex); 
     951            pj_sem_wait(sf->sem); 
     952            pj_mutex_lock(sf->mutex); 
     953        } 
     954 
     955        itBegin = &sf->streams; 
     956        for (it = itBegin->next; it != itBegin; it = it->next) { 
     957            if ((strm && it->stream != strm) || it->stream->is_quitting) 
     958                continue; 
     959 
     960            if (!it->stream->is_initialized) { 
     961#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
     962                delegate->strm = it->stream; 
     963                [delegate performSelectorOnMainThread:@selector(sdl_create) 
     964                          withObject:nil waitUntilDone:YES]; 
     965#else /* PJ_DARWINOS */ 
     966                sdl_create(it->stream); 
     967#endif /* PJ_DARWINOS */ 
     968            } 
     969 
     970#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
     971            delegate->strm = it->stream; 
     972            [delegate performSelectorOnMainThread:@selector(detect_fmt_change) 
     973                      withObject:nil waitUntilDone:YES]; 
     974            [delegate performSelectorOnMainThread:@selector(put_frame) 
     975                      withObject:nil waitUntilDone:YES]; 
     976#else /* PJ_DARWINOS */ 
     977            detect_fmt_change(it->stream); 
     978            put_frame(it->stream, &it->stream->frame); 
     979#endif /* PJ_DARWINOS */ 
     980        } 
     981 
     982#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
     983        delegate->sf = sf; 
     984        delegate->strm = strm; 
     985        [delegate performSelectorOnMainThread:@selector(handle_event) 
     986                  withObject:nil waitUntilDone:YES]; 
     987        ev_stream = delegate->strm; 
     988        ev_type = delegate->ev_type; 
     989#else /* PJ_DARWINOS */ 
     990        ev_stream = handle_event(sf, strm, &ev_type); 
     991#endif /* PJ_DARWINOS */ 
     992 
     993        itBegin = &sf->streams; 
     994        for (it = itBegin->next; it != itBegin; it = it->next) { 
     995            if ((strm && it->stream != strm) || !it->stream->is_quitting || 
     996                it->stream->is_destroyed) 
     997                continue; 
     998 
     999#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
     1000            delegate->strm = it->stream; 
     1001            [delegate performSelectorOnMainThread:@selector(sdl_destroy) 
     1002                      withObject:nil waitUntilDone:YES]; 
    8721003#   if !(SDL_VERSION_ATLEAST(1,3,0)) 
    873     [strm->delegate performSelectorOnMainThread:@selector(sdl_quit) 
    874                     withObject:nil waitUntilDone:YES]; 
     1004            [delegate performSelectorOnMainThread:@selector(sdl_quit) 
     1005                      withObject:nil waitUntilDone:YES]; 
    8751006#   endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */ 
    8761007#else /* PJ_DARWINOS */ 
    877     sdl_create(strm); 
    878     while(!strm->is_quitting) { 
    879         handle_event(strm); 
    880     } 
    881     sdl_destroy(strm, PJ_TRUE); 
     1008            sdl_destroy(it->stream, PJ_TRUE); 
    8821009#   if !(SDL_VERSION_ATLEAST(1,3,0)) 
    883     SDL_Quit(); 
     1010            SDL_Quit(); 
    8841011#   endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */ 
    8851012#endif /* PJ_DARWINOS */ 
    886     strm->screen = NULL; 
     1013            it->stream->screen = NULL; 
     1014            it->stream->is_destroyed = PJ_TRUE; 
     1015 
     1016            if (ev_type == PJMEDIA_EVENT_WND_CLOSING && 
     1017                it->stream == ev_stream) 
     1018            { 
     1019                pjmedia_event p_event; 
     1020 
     1021                pjmedia_event_init(&p_event, PJMEDIA_EVENT_WND_CLOSED, 
     1022                                   &it->stream->last_ts, 
     1023                                   &it->stream->base.epub); 
     1024                pjmedia_event_publish(&it->stream->base.epub, &p_event); 
     1025 
     1026                /* 
     1027                 * Note: don't access the stream after this point, it 
     1028                 * might have been destroyed 
     1029                 */ 
     1030            } 
     1031 
     1032            if (strm) { 
     1033                pj_mutex_unlock(sf->mutex); 
     1034                return 0; 
     1035            } 
     1036        } 
     1037 
     1038        pj_mutex_unlock(sf->mutex); 
     1039    } 
     1040 
     1041on_error: 
     1042#if SDL_VERSION_ATLEAST(1,3,0) 
     1043#   if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
     1044    [delegate performSelectorOnMainThread:@selector(sdl_quit)  
     1045              withObject:nil waitUntilDone:YES]; 
     1046    [delegate release]; 
     1047    [apool release]; 
     1048#   else /* PJ_DARWINOS */ 
     1049    SDL_Quit(); 
     1050#   endif /* PJ_DARWINOS */ 
     1051#endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
    8871052 
    8881053    return 0; 
    889 } 
    890  
    891 static pj_status_t put_frame(struct sdl_stream *stream, 
    892                              const pjmedia_frame *frame) 
    893 { 
    894     pj_status_t status = PJ_SUCCESS; 
    895  
    896     stream->last_ts.u64 = frame->timestamp.u64; 
    897  
    898     if (!stream->is_running) { 
    899         stream->render_exited = PJ_TRUE; 
    900         goto on_return; 
    901     } 
    902  
    903     if (frame->size==0 || frame->buf==NULL || 
    904         frame->size < stream->vafp.framebytes) 
    905         goto on_return; 
    906  
    907     if (stream->surf) { 
    908         if (SDL_MUSTLOCK(stream->surf)) { 
    909             if (SDL_LockSurface(stream->surf) < 0) { 
    910                 PJ_LOG(3, (THIS_FILE, "Unable to lock SDL surface")); 
    911                 status = PJMEDIA_EVID_NOTREADY; 
    912                 goto on_return; 
    913             } 
    914         } 
    915          
    916         pj_memcpy(stream->surf->pixels, frame->buf, 
    917                   stream->vafp.framebytes); 
    918          
    919         if (SDL_MUSTLOCK(stream->surf)) { 
    920             SDL_UnlockSurface(stream->surf); 
    921         } 
    922         SDL_BlitSurface(stream->surf, NULL, stream->screen, &stream->dstrect); 
    923 #if SDL_VERSION_ATLEAST(1,3,0) 
    924         SDL_UpdateWindowSurface(stream->window); 
    925 #else /* SDL_VERSION_ATLEAST(1,3,0) */ 
    926         SDL_UpdateRect(stream->screen, 0, 0, 0, 0); 
    927 #endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
    928     } else if (stream->overlay) { 
    929         int i, sz, offset; 
    930          
    931         if (SDL_LockYUVOverlay(stream->overlay) < 0) { 
    932             PJ_LOG(3, (THIS_FILE, "Unable to lock SDL overlay")); 
    933             status = PJMEDIA_EVID_NOTREADY; 
    934             goto on_return; 
    935         } 
    936          
    937         for (i = 0, offset = 0; i < stream->overlay->planes; i++) { 
    938             sz = stream->vafp.plane_bytes[i]; 
    939             pj_memcpy(stream->overlay->pixels[i], 
    940                       (char *)frame->buf + offset, sz); 
    941             offset += sz; 
    942         } 
    943          
    944         SDL_UnlockYUVOverlay(stream->overlay); 
    945         SDL_DisplayYUVOverlay(stream->overlay, &stream->dstrect); 
    946     } 
    947 #if SDL_VERSION_ATLEAST(1,3,0) 
    948     else if (stream->scr_tex) { 
    949         if (stream->tex_buf) 
    950             pj_memcpy(stream->tex_buf, frame->buf, stream->vafp.framebytes); 
    951         else 
    952             draw_texture(stream, frame->buf); 
    953     } 
    954 #endif /* SDL_VERSION_ATLEAST(1,3,0) */ 
    955 #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 
    956     else if (stream->param.rend_id == OPENGL_DEV_IDX) { 
    957         if (stream->tex_buf) 
    958             pj_memcpy(stream->tex_buf, frame->buf, stream->vafp.framebytes); 
    959         else 
    960             draw_gl(stream, frame->buf); 
    961     } 
    962 #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 
    963  
    964 on_return: 
    965     stream->status = status; 
    966     return status; 
    9671054} 
    9681055 
     
    9731060    struct sdl_stream *stream = (struct sdl_stream*)strm; 
    9741061 
    975 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    976     stream->frame = frame;     
    977     [stream->delegate performSelectorOnMainThread:@selector(put_frame)  
    978                       withObject:nil waitUntilDone:YES]; 
    979  
    980     return stream->status; 
    981 #else /* PJ_DARWINOS */ 
    982     return put_frame(stream, frame); 
    983 #endif /* PJ_DARWINOS */ 
     1062    stream->last_ts.u64 = frame->timestamp.u64; 
     1063 
     1064    if (!stream->is_running) { 
     1065        stream->render_exited = PJ_TRUE; 
     1066        return PJ_SUCCESS; 
     1067    } 
     1068 
     1069    if (frame->size==0 || frame->buf==NULL || 
     1070        frame->size < stream->vafp.framebytes) 
     1071        return PJ_SUCCESS; 
     1072 
     1073    pj_memcpy(stream->frame.buf, frame->buf, stream->vafp.framebytes); 
     1074 
     1075    return PJ_SUCCESS; 
    9841076} 
    9851077 
     
    9991091    PJ_ASSERT_RETURN(param->dir == PJMEDIA_DIR_RENDER, PJ_EINVAL); 
    10001092 
     1093#if !SDL_VERSION_ATLEAST(1,3,0) 
     1094    /* Prior to 1.3, SDL does not support multiple renderers. */ 
     1095    pj_mutex_lock(sf->mutex); 
     1096    if (!pj_list_empty(&sf->streams) { 
     1097        pj_mutex_unlock(sf->mutex); 
     1098        return PJMEDIA_EVID_NOTREADY; 
     1099    } 
     1100    pj_mutex_unlock(sf->mutex); 
     1101#endif 
     1102 
    10011103    /* Create and Initialize stream descriptor */ 
    10021104    pool = pj_pool_create(sf->pf, "sdl-dev", 1000, 1000, NULL); 
     
    10061108    pj_memcpy(&strm->param, param, sizeof(*param)); 
    10071109    strm->pool = pool; 
     1110    strm->sf = sf; 
    10081111    pj_memcpy(&strm->vid_cb, cb, sizeof(*cb)); 
    10091112    strm->user_data = user_data; 
    10101113    pjmedia_event_publisher_init(&strm->base.epub, PJMEDIA_SIG_VID_DEV_SDL); 
     1114    pj_list_init(&strm->list_entry); 
     1115    strm->list_entry.stream = strm; 
    10111116 
    10121117    /* Create render stream here */ 
    10131118    if (param->dir & PJMEDIA_DIR_RENDER) { 
     1119        struct sdl_dev_t sdl_dev; 
     1120 
    10141121        strm->status = PJ_SUCCESS; 
    1015 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    1016         strm->apool = [[NSAutoreleasePool alloc] init]; 
    1017         strm->delegate = [[SDLDelegate alloc]init]; 
    1018         strm->delegate->strm = strm; 
    1019         /* On Darwin OS, we need to call SDL functions in the main thread */ 
    1020         [strm->delegate performSelectorOnMainThread:@selector(sdl_create) 
    1021                         withObject:nil waitUntilDone:YES]; 
    1022         if ((status = strm->status) != PJ_SUCCESS) { 
    1023             goto on_error; 
    1024         } 
    1025 #endif /* PJ_DARWINOS */ 
    1026         status = pj_thread_create(pool, "sdl_thread", sdl_thread, 
    1027                                   strm, 0, 0, &strm->sdl_thread); 
    1028  
     1122        sdl_dev.sf = strm->sf; 
     1123        sdl_dev.strm = strm; 
     1124        pj_mutex_lock(strm->sf->mutex); 
     1125#if !SDL_USE_ONE_THREAD_PER_DISPLAY 
     1126        if (pj_list_empty(&strm->sf->streams)) 
     1127            pj_sem_post(strm->sf->sem); 
     1128#endif /* !SDL_USE_ONE_THREAD_PER_DISPLAY */ 
     1129        pj_list_insert_after(&strm->sf->streams, &strm->list_entry); 
     1130        pj_mutex_unlock(strm->sf->mutex); 
     1131 
     1132#if SDL_USE_ONE_THREAD_PER_DISPLAY 
     1133        status = pj_thread_create(pool, "sdl_thread", sdl_thread, 
     1134                                  &sdl_dev, 0, 0, &strm->sdl_thread); 
    10291135        if (status != PJ_SUCCESS) { 
    10301136            goto on_error; 
    10311137        } 
     1138#endif /* SDL_USE_ONE_THREAD_PER_DISPLAY */ 
    10321139 
    10331140        while(strm->status == PJ_SUCCESS && !strm->surf && !strm->overlay 
     
    11911298    if (cap == PJMEDIA_VID_DEV_CAP_FORMAT) { 
    11921299        strm->new_fmt = (pjmedia_format *)pval; 
    1193 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    1194         [strm->delegate performSelectorOnMainThread: 
    1195                         @selector(detect_fmt_change) 
    1196                         withObject:nil waitUntilDone:YES]; 
    1197 #endif /* PJ_DARWINOS */ 
    11981300        while (strm->new_fmt) 
    11991301            pj_thread_sleep(10); 
     
    12071309             */ 
    12081310            strm->new_fmt = &strm->param.fmt; 
    1209 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    1210             [strm->delegate performSelectorOnMainThread: 
    1211                             @selector(detect_fmt_change) 
    1212                             withObject:nil waitUntilDone:YES]; 
    1213 #endif /* PJ_DARWINOS */ 
    12141311            while (strm->new_fmt) 
    12151312                pj_thread_sleep(10); 
     
    12291326    } else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE) { 
    12301327        strm->new_disp_size = (pjmedia_rect_size *)pval; 
    1231 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    1232         [strm->delegate performSelectorOnMainThread: 
    1233                         @selector(detect_fmt_change) 
    1234                         withObject:nil waitUntilDone:YES]; 
    1235 #endif /* PJ_DARWINOS */ 
    12361328        while (strm->new_disp_size) 
    12371329            pj_thread_sleep(10); 
     
    12661358    /* Wait for renderer put_frame() to finish */ 
    12671359    stream->is_running = PJ_FALSE; 
    1268 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    1269     if (![NSThread isMainThread]) 
    1270 #endif /* PJ_DARWINOS */ 
    12711360    for (i=0; !stream->render_exited && i<50; ++i) 
    12721361        pj_thread_sleep(10); 
     
    12891378        if (stream->sdl_thread) 
    12901379            pj_thread_join(stream->sdl_thread); 
    1291     } 
    1292  
    1293 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    1294     if (stream->delegate) { 
    1295         [stream->delegate release]; 
    1296         stream->delegate = NULL; 
    1297     } 
    1298     if (stream->apool) { 
    1299         [stream->apool release]; 
    1300         stream->apool = NULL; 
    1301     } 
    1302 #endif /* PJ_DARWINOS */ 
     1380        while (!stream->is_destroyed) { 
     1381            pj_thread_sleep(10); 
     1382        } 
     1383    } 
     1384 
     1385    pj_mutex_lock(stream->sf->mutex); 
     1386    if (!pj_list_empty(&stream->list_entry)) 
     1387        pj_list_erase(&stream->list_entry); 
     1388    pj_mutex_unlock(stream->sf->mutex); 
     1389 
    13031390    pj_pool_release(stream->pool); 
    1304      
    13051391 
    13061392    return PJ_SUCCESS; 
     
    13131399    if (SDL_Init(SDL_INIT_VIDEO)) { 
    13141400        PJ_LOG(4, (THIS_FILE, "Cannot initialize SDL")); 
    1315     } 
     1401        status = PJMEDIA_EVID_INIT; 
     1402    } 
     1403    status = PJ_SUCCESS; 
    13161404} 
    13171405 
     
    13381426- (void)handle_event 
    13391427{ 
    1340     handle_event(strm); 
     1428    strm = handle_event(sf, strm, &ev_type); 
    13411429} 
    13421430 
    13431431- (void)put_frame 
    13441432{ 
    1345     put_frame(strm, strm->frame); 
     1433    put_frame(strm, &strm->frame); 
    13461434} 
    13471435 
Note: See TracChangeset for help on using the changeset viewer.