Changeset 3718 for pjproject/trunk/pjmedia/src/pjmedia-videodev/sdl_dev.c
- Timestamp:
- Aug 24, 2011 5:54:25 AM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia-videodev/sdl_dev.c
r3715 r3718 17 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 18 */ 19 #include <pjmedia/converter.h>20 19 #include <pjmedia-videodev/videodev_imp.h> 21 20 #include <pj/assert.h> … … 24 23 25 24 #if defined(PJMEDIA_VIDEO_DEV_HAS_SDL) && PJMEDIA_VIDEO_DEV_HAS_SDL != 0 26 27 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=028 # include "TargetConditionals.h"29 # include <Foundation/Foundation.h>30 # define SDL_USE_ONE_THREAD_PER_DISPLAY 131 #elif defined(PJ_WIN32) && PJ_WIN32 != 032 # define SDL_USE_ONE_THREAD_PER_DISPLAY 133 #else34 # define SDL_USE_ONE_THREAD_PER_DISPLAY 035 #endif36 25 37 26 #include <SDL.h> … … 42 31 #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 43 32 33 #if !(SDL_VERSION_ATLEAST(1,3,0)) 34 # error "SDL 1.3 or later is required" 35 #endif 36 37 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 38 # include "TargetConditionals.h" 39 # include <Foundation/Foundation.h> 40 #endif 41 44 42 #define THIS_FILE "sdl_dev.c" 45 43 #define DEFAULT_CLOCK_RATE 90000 … … 47 45 #define DEFAULT_HEIGHT 480 48 46 #define DEFAULT_FPS 25 49 50 #if !(SDL_VERSION_ATLEAST(1,3,0))51 # define SDL_PIXELFORMAT_RGBA8888 052 # define SDL_PIXELFORMAT_RGB24 053 # define SDL_PIXELFORMAT_BGRA8888 054 # define SDL_PIXELFORMAT_ABGR8888 055 # define SDL_PIXELFORMAT_BGR24 056 # define SDL_PIXELFORMAT_ARGB8888 057 # define SDL_PIXELFORMAT_RGB24 058 #endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */59 47 60 48 typedef struct sdl_fmt_info … … 98 86 }; 99 87 100 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0101 @interface SDLDelegate: NSObject102 {103 @public104 struct sdl_stream *strm;105 struct sdl_factory *sf;106 pjmedia_event_type ev_type;107 pj_status_t status;108 }109 110 - (void)sdl_init;111 - (void)sdl_quit;112 - (void)detect_fmt_change;113 - (void)sdl_create;114 - (void)sdl_destroy;115 - (void)handle_event;116 - (void)put_frame;117 @end118 #endif /* PJ_DARWINOS */119 120 88 /* sdl_ device info */ 121 89 struct sdl_dev_info … … 131 99 }; 132 100 101 #define MAX_JOBS 8 102 103 typedef pj_status_t (*job_func_ptr)(void *data); 104 105 typedef struct job { 106 job_func_ptr func; 107 void *data; 108 unsigned flags; 109 pj_status_t retval; 110 } job; 111 112 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 113 @interface JQDelegate: NSObject 114 { 115 @public 116 job *pjob; 117 } 118 119 - (void)run_job; 120 @end 121 122 @implementation JQDelegate 123 - (void)run_job 124 { 125 pjob->retval = (*pjob->func)(pjob->data); 126 } 127 @end 128 #endif /* PJ_DARWINOS */ 129 130 typedef struct job_queue { 131 job *jobs[MAX_JOBS]; 132 pj_sem_t *job_sem[MAX_JOBS]; 133 pj_mutex_t *mutex; 134 pj_thread_t *thread; 135 pj_sem_t *sem; 136 137 int head, tail; 138 pj_bool_t is_full; 139 pj_bool_t is_quitting; 140 } job_queue; 141 133 142 /* sdl_ factory */ 134 143 struct sdl_factory … … 140 149 unsigned dev_count; 141 150 struct sdl_dev_info *dev_info; 151 job_queue *jq; 142 152 143 153 pj_thread_t *sdl_thread; /**< SDL thread. */ 144 pj_status_t status;145 154 pj_sem_t *sem; 146 155 pj_mutex_t *mutex; 147 156 struct stream_list streams; 148 157 pj_bool_t is_quitting; 158 pj_thread_desc thread_desc; 159 pj_thread_t *ev_thread; 149 160 }; 150 161 … … 159 170 void *user_data; /**< Application data. */ 160 171 161 pj_thread_t *sdl_thread; /**< SDL thread. */ 162 pj_bool_t is_initialized; 163 pj_bool_t is_quitting; 164 pj_bool_t is_destroyed; 172 struct sdl_factory *sf; 173 const pjmedia_frame *frame; 165 174 pj_bool_t is_running; 166 pj_bool_t render_exited;167 pj_status_t status;168 pjmedia_format *new_fmt;169 pjmedia_rect_size *new_disp_size;170 175 pj_timestamp last_ts; 171 pjmedia_frame frame;172 pj_size_t frame_buf_size;173 176 struct stream_list list_entry; 174 struct sdl_factory *sf; 175 176 #if SDL_VERSION_ATLEAST(1,3,0) 177 177 178 SDL_Window *window; /**< Display window. */ 178 179 SDL_Renderer *renderer; /**< Display renderer. */ 179 180 SDL_Texture *scr_tex; /**< Screen texture. */ 180 181 int pitch; /**< Pitch value. */ 181 #endif /* SDL_VERSION_ATLEAST(1,3,0) */182 182 SDL_Rect rect; /**< Frame rectangle. */ 183 183 SDL_Rect dstrect; /**< Display rectangle. */ 184 SDL_Surface *screen; /**< Display screen. */185 SDL_Surface *surf; /**< RGB surface. */186 SDL_Overlay *overlay; /**< YUV overlay. */187 184 #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 188 # if SDL_VERSION_ATLEAST(1,3,0)189 185 SDL_GLContext *gl_context; 190 # endif /* SDL_VERSION_ATLEAST(1,3,0) */191 186 GLuint texture; 192 187 #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 193 188 194 189 pjmedia_video_apply_fmt_param vafp; 195 };196 197 struct sdl_dev_t198 {199 struct sdl_factory *sf;200 struct sdl_stream *strm;201 190 }; 202 191 … … 234 223 static pj_status_t sdl_stream_destroy(pjmedia_vid_dev_stream *strm); 235 224 236 static int sdl_thread(void * data); 225 static pj_status_t resize_disp(struct sdl_stream *strm, 226 pjmedia_rect_size *new_disp_size); 227 static pj_status_t sdl_destroy_all(void *data); 228 229 /* Job queue prototypes */ 230 static pj_status_t job_queue_create(pj_pool_t *pool, job_queue **pjq); 231 static pj_status_t job_queue_post_job(job_queue *jq, job_func_ptr func, 232 void *data, unsigned flags, 233 pj_status_t *retval); 234 static pj_status_t job_queue_destroy(job_queue *jq); 237 235 238 236 /* Operations */ … … 281 279 } 282 280 281 static pj_status_t sdl_init(void * data) 282 { 283 PJ_UNUSED_ARG(data); 284 285 if (SDL_Init(SDL_INIT_VIDEO)) { 286 PJ_LOG(3, (THIS_FILE, "Failed initializing SDL")); 287 return PJMEDIA_EVID_INIT; 288 } 289 290 return PJ_SUCCESS; 291 } 292 293 static struct sdl_stream* find_stream(struct sdl_factory *sf, 294 Uint32 windowID, 295 pjmedia_event *pevent) 296 { 297 struct stream_list *it, *itBegin; 298 struct sdl_stream *strm = NULL; 299 300 itBegin = &sf->streams; 301 for (it = itBegin->next; it != itBegin; it = it->next) { 302 if (SDL_GetWindowID(it->stream->window) == windowID) 303 { 304 strm = it->stream; 305 break; 306 } 307 } 308 309 if (strm) 310 pjmedia_event_init(pevent, PJMEDIA_EVENT_NONE, &strm->last_ts, 311 &strm->base.epub); 312 313 return strm; 314 } 315 316 static pj_status_t handle_event(void *data) 317 { 318 struct sdl_factory *sf = (struct sdl_factory*)data; 319 SDL_Event sevent; 320 321 if (!pj_thread_is_registered()) 322 pj_thread_register("sdl_ev", sf->thread_desc, &sf->ev_thread); 323 324 while (SDL_PollEvent(&sevent)) { 325 struct sdl_stream *strm = NULL; 326 pjmedia_event pevent; 327 328 pj_mutex_lock(sf->mutex); 329 pevent.type = PJMEDIA_EVENT_NONE; 330 switch(sevent.type) { 331 case SDL_MOUSEBUTTONDOWN: 332 strm = find_stream(sf, sevent.button.windowID, &pevent); 333 pevent.type = PJMEDIA_EVENT_MOUSE_BTN_DOWN; 334 break; 335 case SDL_WINDOWEVENT: 336 strm = find_stream(sf, sevent.window.windowID, &pevent); 337 switch (sevent.window.event) { 338 case SDL_WINDOWEVENT_RESIZED: 339 pevent.type = PJMEDIA_EVENT_WND_RESIZED; 340 pevent.data.wnd_resized.new_size.w = 341 sevent.window.data1; 342 pevent.data.wnd_resized.new_size.h = 343 sevent.window.data2; 344 break; 345 case SDL_WINDOWEVENT_CLOSE: 346 pevent.type = PJMEDIA_EVENT_WND_CLOSING; 347 break; 348 } 349 break; 350 default: 351 break; 352 } 353 354 if (strm && pevent.type != PJMEDIA_EVENT_NONE) { 355 pj_status_t status; 356 357 pjmedia_event_publish(&strm->base.epub, &pevent); 358 359 switch (pevent.type) { 360 case PJMEDIA_EVENT_WND_RESIZED: 361 status = resize_disp(strm, &pevent.data.wnd_resized.new_size); 362 if (status != PJ_SUCCESS) 363 PJ_LOG(3, (THIS_FILE, "Failed resizing the display.")); 364 break; 365 case PJMEDIA_EVENT_WND_CLOSING: 366 if (pevent.data.wnd_closing.cancel) { 367 /* Cancel the closing operation */ 368 break; 369 } 370 371 /* Proceed to cleanup SDL. App must still call 372 * pjmedia_dev_stream_destroy() when getting WND_CLOSED 373 * event 374 */ 375 sdl_stream_stop(&strm->base); 376 sdl_destroy_all(strm); 377 pjmedia_event_init(&pevent, PJMEDIA_EVENT_WND_CLOSED, 378 &strm->last_ts, 379 &strm->base.epub); 380 pjmedia_event_publish(&strm->base.epub, &pevent); 381 382 /* 383 * Note: don't access the stream after this point, it 384 * might have been destroyed 385 */ 386 break; 387 default: 388 /* Just to prevent gcc warning about unused enums */ 389 break; 390 } 391 } 392 393 pj_mutex_unlock(sf->mutex); 394 } 395 396 return PJ_SUCCESS; 397 } 398 399 static int sdl_ev_thread(void *data) 400 { 401 struct sdl_factory *sf = (struct sdl_factory*)data; 402 403 while(1) { 404 pj_status_t status; 405 406 pj_mutex_lock(sf->mutex); 407 if (pj_list_empty(&sf->streams)) { 408 pj_mutex_unlock(sf->mutex); 409 /* Wait until there is any stream. */ 410 pj_sem_wait(sf->sem); 411 } else 412 pj_mutex_unlock(sf->mutex); 413 414 if (sf->is_quitting) 415 break; 416 417 job_queue_post_job(sf->jq, handle_event, sf, 0, &status); 418 419 pj_thread_sleep(50); 420 } 421 422 return 0; 423 } 424 425 static pj_status_t sdl_quit(void *data) 426 { 427 PJ_UNUSED_ARG(data); 428 SDL_Quit(); 429 return PJ_SUCCESS; 430 } 431 283 432 /* API: init factory */ 284 433 static pj_status_t sdl_factory_init(pjmedia_vid_dev_factory *f) … … 287 436 struct sdl_dev_info *ddi; 288 437 unsigned i, j; 289 struct sdl_dev_t sdl_dev;290 438 pj_status_t status; 291 439 SDL_version version; 440 441 status = job_queue_create(sf->pool, &sf->jq); 442 if (status != PJ_SUCCESS) 443 return PJMEDIA_EVID_INIT; 444 445 job_queue_post_job(sf->jq, sdl_init, NULL, 0, &status); 446 if (status != PJ_SUCCESS) 447 return status; 292 448 293 449 pj_list_init(&sf->streams); … … 301 457 return status; 302 458 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) { 309 return PJMEDIA_EVID_INIT; 310 } 311 312 while (sf->status == PJ_EUNKNOWN) 313 pj_thread_sleep(10); 314 315 if (sf->status != PJ_SUCCESS) 316 return sf->status; 459 /* Create event handler thread. */ 460 status = pj_thread_create(sf->pool, "sdl_thread", sdl_ev_thread, 461 sf, 0, 0, &sf->sdl_thread); 462 if (status != PJ_SUCCESS) 463 return status; 317 464 318 465 sf->dev_count = 1; … … 346 493 ddi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT | 347 494 PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE; 348 #if SDL_VERSION_ATLEAST(1,3,0)349 495 ddi->info.caps |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW; 350 #endif /* SDL_VERSION_ATLEAST(1,3,0) */351 496 352 497 for (j = 0; j < ddi->info.fmt_cnt; j++) { … … 370 515 struct sdl_factory *sf = (struct sdl_factory*)f; 371 516 pj_pool_t *pool = sf->pool; 517 pj_status_t status; 372 518 373 519 pj_assert(pj_list_empty(&sf->streams)); … … 388 534 sf->sem = NULL; 389 535 } 536 537 job_queue_post_job(sf->jq, sdl_quit, NULL, 0, &status); 538 job_queue_destroy(sf->jq); 390 539 391 540 sf->pool = NULL; … … 462 611 } 463 612 464 static void sdl_destroy(struct sdl_stream *strm, pj_bool_t destroy_win) 465 { 466 PJ_UNUSED_ARG(destroy_win); 467 468 if (strm->surf) { 469 SDL_FreeSurface(strm->surf); 470 strm->surf = NULL; 471 } 472 if (strm->overlay) { 473 SDL_FreeYUVOverlay(strm->overlay); 474 strm->overlay = NULL; 475 } 613 static pj_status_t sdl_destroy(void *data) 614 { 615 struct sdl_stream *strm = (struct sdl_stream *)data; 616 476 617 #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 477 618 if (strm->texture) { … … 479 620 strm->texture = 0; 480 621 } 481 #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */482 #if SDL_VERSION_ATLEAST(1,3,0)483 # if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL484 622 if (strm->gl_context) { 485 623 SDL_GL_DeleteContext(strm->gl_context); 486 624 strm->gl_context = NULL; 487 625 } 488 # 626 #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 489 627 if (strm->scr_tex) { 490 628 SDL_DestroyTexture(strm->scr_tex); … … 495 633 strm->renderer = NULL; 496 634 } 497 # if !defined(TARGET_OS_IPHONE) || TARGET_OS_IPHONE == 0 498 if (destroy_win) { 499 if (strm->window && 500 !(strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW)) 501 { 502 SDL_DestroyWindow(strm->window); 503 } 504 strm->window = NULL; 505 } 506 # endif /* TARGET_OS_IPHONE */ 507 #endif /* SDL_VERSION_ATLEAST(1,3,0) */ 508 } 509 510 static pj_status_t sdl_create_view(struct sdl_stream *strm, 511 pjmedia_format *fmt) 512 { 513 sdl_fmt_info *sdl_info = get_sdl_format_info(fmt->id); 635 636 return PJ_SUCCESS; 637 } 638 639 static pj_status_t sdl_destroy_all(void *data) 640 { 641 struct sdl_stream *strm = (struct sdl_stream *)data; 642 643 sdl_destroy(data); 644 #if !defined(TARGET_OS_IPHONE) || TARGET_OS_IPHONE == 0 645 if (strm->window && 646 !(strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW)) 647 { 648 SDL_DestroyWindow(strm->window); 649 } 650 strm->window = NULL; 651 #endif /* TARGET_OS_IPHONE */ 652 653 return PJ_SUCCESS; 654 } 655 656 static pj_status_t sdl_create_rend(struct sdl_stream * strm, 657 pjmedia_format *fmt) 658 { 659 sdl_fmt_info *sdl_info; 514 660 const pjmedia_video_format_info *vfi; 515 661 pjmedia_video_format_detail *vfd; 516 662 663 fmt = &strm->param.fmt; 664 sdl_info = get_sdl_format_info(fmt->id); 517 665 vfi = pjmedia_get_video_format_info(pjmedia_video_format_mgr_instance(), 518 666 fmt->id); … … 537 685 strm->dstrect.h = (Uint16)strm->param.disp_size.h; 538 686 539 sdl_destroy(strm, PJ_FALSE); 540 541 #if SDL_VERSION_ATLEAST(1,3,0) 687 sdl_destroy(strm); 688 689 #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 690 if (strm->param.rend_id == OPENGL_DEV_IDX) { 691 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); 692 } 693 #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 694 542 695 if (!strm->window) { 543 Uint32 flags = SDL_WINDOW_SHOWN | /*SDL_WINDOW_RESIZABLE*/ 544 SDL_WINDOW_BORDERLESS; 545 546 # if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 696 Uint32 flags = /*SDL_WINDOW_RESIZABLE; */ SDL_WINDOW_BORDERLESS; 697 698 if (!((strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE) && 699 strm->param.window_hide)) 700 flags |= SDL_WINDOW_SHOWN; 701 702 #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 547 703 if (strm->param.rend_id == OPENGL_DEV_IDX) 548 704 flags |= SDL_WINDOW_OPENGL; 549 # 705 #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 550 706 551 707 if (strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) { 552 708 /* Use the window supplied by the application. */ 553 strm->window = SDL_CreateWindowFrom(strm->param.window.info.window); 709 strm->window = SDL_CreateWindowFrom( 710 strm->param.window.info.window); 554 711 } else { 555 712 /* Create the window where we will draw. */ … … 565 722 } 566 723 567 SDL_SetWindowSize(strm->window, strm->param.disp_size.w,568 strm->param.disp_size.h);569 570 724 /** 571 725 * We must call SDL_CreateRenderer in order for draw calls to … … 576 730 return PJMEDIA_EVID_SYSERR; 577 731 578 # 732 #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 579 733 if (strm->param.rend_id == OPENGL_DEV_IDX) { 580 734 strm->gl_context = SDL_GL_CreateContext(strm->window); … … 582 736 return PJMEDIA_EVID_SYSERR; 583 737 SDL_GL_MakeCurrent(strm->window, strm->gl_context); 584 } 585 # endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 586 587 strm->screen = SDL_GetWindowSurface(strm->window); 588 589 #else /* SDL_VERSION_ATLEAST(1,3,0) */ 590 /* Initialize the display */ 591 strm->screen = SDL_SetVideoMode(strm->param.disp_size.w, 592 strm->param.disp_size.h, 0, ( 593 # if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 594 strm->param.rend_id == OPENGL_DEV_IDX? 595 SDL_OPENGL | SDL_RESIZABLE: 596 # endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 597 SDL_RESIZABLE | SDL_SWSURFACE)); 598 if (strm->screen == NULL) 599 return PJMEDIA_EVID_SYSERR; 600 601 SDL_WM_SetCaption("pjmedia-SDL video", NULL); 602 603 #endif /* SDL_VERSION_ATLEAST(1,3,0) */ 604 605 #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 606 if (strm->param.rend_id == OPENGL_DEV_IDX) { 607 /* Init some OpenGL settings */ 738 739 /* Init some OpenGL settings */ 608 740 glDisable(GL_DEPTH_TEST); 609 741 glDisable(GL_CULL_FACE); … … 629 761 } else 630 762 #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 631 #if SDL_VERSION_ATLEAST(1,3,0)632 763 { 633 764 strm->scr_tex = SDL_CreateTexture(strm->renderer, sdl_info->sdl_format, … … 639 770 strm->pitch = strm->rect.w * SDL_BYTESPERPIXEL(sdl_info->sdl_format); 640 771 } 641 #else /* SDL_VERSION_ATLEAST(1,3,0) */ 642 if (vfi->color_model == PJMEDIA_COLOR_MODEL_RGB) { 643 strm->surf = SDL_CreateRGBSurface(SDL_SWSURFACE, 644 strm->rect.w, strm->rect.h, 645 vfi->bpp, 646 sdl_info->Rmask, 647 sdl_info->Gmask, 648 sdl_info->Bmask, 649 sdl_info->Amask); 650 if (strm->surf == NULL) 651 return PJMEDIA_EVID_SYSERR; 652 } else if (vfi->color_model == PJMEDIA_COLOR_MODEL_YUV) { 653 strm->overlay = SDL_CreateYUVOverlay(strm->rect.w, strm->rect.h, 654 sdl_info->sdl_format, 655 strm->screen); 656 if (strm->overlay == NULL) 657 return PJMEDIA_EVID_SYSERR; 658 } 659 #endif /* SDL_VERSION_ATLEAST(1,3,0) */ 660 661 if (strm->vafp.framebytes > strm->frame_buf_size) { 662 strm->frame_buf_size = strm->vafp.framebytes; 663 strm->frame.buf = pj_pool_alloc(strm->pool, strm->vafp.framebytes); 664 } 665 666 return PJ_SUCCESS; 667 } 668 669 static pj_status_t sdl_create(struct sdl_stream *strm) 670 { 671 strm->is_initialized = PJ_TRUE; 672 673 #if !(SDL_VERSION_ATLEAST(1,3,0)) 674 if (SDL_Init(SDL_INIT_VIDEO)) { 675 strm->status = PJMEDIA_EVID_INIT; 676 return strm->status; 677 } 678 #endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */ 679 772 773 return PJ_SUCCESS; 774 } 775 776 static pj_status_t sdl_create(void *data) 777 { 778 struct sdl_stream *strm = (struct sdl_stream *)data; 779 return sdl_create_rend(strm, &strm->param.fmt); 780 } 781 782 static pj_status_t resize_disp(struct sdl_stream *strm, 783 pjmedia_rect_size *new_disp_size) 784 { 785 pj_memcpy(&strm->param.disp_size, new_disp_size, 786 sizeof(strm->param.disp_size)); 787 788 if (strm->scr_tex) { 789 strm->dstrect.x = strm->dstrect.y = 0; 790 strm->dstrect.w = (Uint16)strm->param.disp_size.w; 791 strm->dstrect.h = (Uint16)strm->param.disp_size.h; 792 SDL_RenderSetViewport(strm->renderer, &strm->dstrect); 793 } 680 794 #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 681 if (strm->param.rend_id == OPENGL_DEV_IDX) {682 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);795 else if (strm->param.rend_id == OPENGL_DEV_IDX) { 796 sdl_create_rend(strm, &strm->param.fmt); 683 797 } 684 798 #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 685 799 686 strm->status = sdl_create_view(strm, &strm->param.fmt); 687 return strm->status; 688 } 689 690 static void detect_fmt_change(struct sdl_stream *strm) 691 { 692 strm->status = PJ_SUCCESS; 693 if (strm->new_fmt || strm->new_disp_size) { 694 if (strm->new_disp_size) { 695 pj_memcpy(&strm->param.disp_size, strm->new_disp_size, 696 sizeof(strm->param.disp_size)); 697 #if SDL_VERSION_ATLEAST(1,3,0) 698 if (strm->scr_tex) { 699 strm->dstrect.x = strm->dstrect.y = 0; 700 strm->dstrect.w = (Uint16)strm->param.disp_size.w; 701 strm->dstrect.h = (Uint16)strm->param.disp_size.h; 702 SDL_RenderSetViewport(strm->renderer, &strm->dstrect); 703 strm->new_fmt = NULL; 704 strm->new_disp_size = NULL; 705 return; 706 } 707 #endif 708 } 709 710 /* Re-initialize SDL */ 711 strm->status = sdl_create_view(strm, (strm->new_fmt? strm->new_fmt : 712 &strm->param.fmt)); 713 714 if (strm->status == PJ_SUCCESS) { 715 if (strm->new_fmt) 716 pjmedia_format_copy(&strm->param.fmt, strm->new_fmt); 717 } 718 strm->new_fmt = NULL; 719 strm->new_disp_size = NULL; 720 } 721 } 722 723 static pj_status_t put_frame(struct sdl_stream *stream, 724 const pjmedia_frame *frame) 725 { 726 if (!stream->is_running) 727 return PJ_SUCCESS; 728 729 if (stream->surf) { 730 if (SDL_MUSTLOCK(stream->surf)) { 731 if (SDL_LockSurface(stream->surf) < 0) { 732 PJ_LOG(3, (THIS_FILE, "Unable to lock SDL surface")); 733 return PJMEDIA_EVID_NOTREADY; 734 } 735 } 736 737 pj_memcpy(stream->surf->pixels, frame->buf, 738 stream->vafp.framebytes); 739 740 if (SDL_MUSTLOCK(stream->surf)) { 741 SDL_UnlockSurface(stream->surf); 742 } 743 #if SDL_VERSION_ATLEAST(1,3,0) 744 SDL_UpdateWindowSurface(stream->window); 745 #else /* SDL_VERSION_ATLEAST(1,3,0) */ 746 SDL_BlitSurface(stream->surf, NULL, stream->screen, &stream->dstrect); 747 #endif /* SDL_VERSION_ATLEAST(1,3,0) */ 748 } else if (stream->overlay) { 749 int i, sz, offset; 750 751 if (SDL_LockYUVOverlay(stream->overlay) < 0) { 752 PJ_LOG(3, (THIS_FILE, "Unable to lock SDL overlay")); 753 return PJMEDIA_EVID_NOTREADY; 754 } 755 756 for (i = 0, offset = 0; i < stream->overlay->planes; i++) { 757 sz = stream->vafp.plane_bytes[i]; 758 pj_memcpy(stream->overlay->pixels[i], 759 (char *)frame->buf + offset, sz); 760 offset += sz; 761 } 762 763 SDL_UnlockYUVOverlay(stream->overlay); 764 SDL_DisplayYUVOverlay(stream->overlay, &stream->dstrect); 765 } 766 #if SDL_VERSION_ATLEAST(1,3,0) 767 else if (stream->scr_tex) { 800 return PJ_SUCCESS; 801 } 802 803 static pj_status_t change_format(struct sdl_stream *strm, 804 pjmedia_format *new_fmt) 805 { 806 pj_status_t status; 807 808 /* Recreate SDL renderer */ 809 status = sdl_create_rend(strm, (new_fmt? new_fmt : 810 &strm->param.fmt)); 811 if (status == PJ_SUCCESS && new_fmt) 812 pjmedia_format_copy(&strm->param.fmt, new_fmt); 813 814 return status; 815 } 816 817 static pj_status_t put_frame(void *data) 818 { 819 struct sdl_stream *stream = (struct sdl_stream *)data; 820 const pjmedia_frame *frame = stream->frame; 821 822 if (stream->scr_tex) { 768 823 SDL_UpdateTexture(stream->scr_tex, NULL, frame->buf, stream->pitch); 769 824 SDL_RenderClear(stream->renderer); … … 772 827 SDL_RenderPresent(stream->renderer); 773 828 } 774 #endif /* SDL_VERSION_ATLEAST(1,3,0) */775 829 #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 776 830 else if (stream->param.rend_id == OPENGL_DEV_IDX && stream->texture) { … … 788 842 glVertex2i(stream->param.disp_size.w, stream->param.disp_size.h); 789 843 glEnd(); 790 # if SDL_VERSION_ATLEAST(1,3,0)791 844 SDL_GL_SwapWindow(stream->window); 792 # else /* SDL_VERSION_ATLEAST(1,3,0) */793 SDL_GL_SwapBuffers();794 # endif /* SDL_VERSION_ATLEAST(1,3,0) */795 845 } 796 846 #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 797 847 798 848 return PJ_SUCCESS; 799 }800 801 static struct sdl_stream* find_stream(struct sdl_factory *sf,802 Uint32 windowID,803 pjmedia_event *pevent)804 {805 struct stream_list *it, *itBegin;806 struct sdl_stream *strm = NULL;807 808 itBegin = &sf->streams;809 for (it = itBegin->next; it != itBegin; it = it->next) {810 #if SDL_VERSION_ATLEAST(1,3,0)811 if (SDL_GetWindowID(it->stream->window) == windowID)812 #else /* SDL_VERSION_ATLEAST(1,3,0) */813 PJ_UNUSED_ARG(windowID);814 #endif /* SDL_VERSION_ATLEAST(1,3,0) */815 {816 strm = it->stream;817 break;818 }819 }820 821 if (strm)822 pjmedia_event_init(pevent, PJMEDIA_EVENT_NONE, &strm->last_ts,823 &strm->base.epub);824 825 return strm;826 }827 828 static int poll_event(struct sdl_factory *sf, pjmedia_event *pevent,829 struct sdl_stream **strm)830 {831 int retval;832 SDL_Event sevent;833 834 retval = SDL_PollEvent(&sevent);835 if (retval) {836 #if !(SDL_VERSION_ATLEAST(1,3,0))837 *strm = find_stream(sf, 0, pevent);838 pj_assert(strm);839 #endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */840 841 switch(sevent.type) {842 case SDL_MOUSEBUTTONDOWN:843 #if SDL_VERSION_ATLEAST(1,3,0)844 *strm = find_stream(sf, sevent.button.windowID, pevent);845 #endif /* SDL_VERSION_ATLEAST(1,3,0) */846 pevent->type = PJMEDIA_EVENT_MOUSE_BTN_DOWN;847 break;848 #if SDL_VERSION_ATLEAST(1,3,0)849 case SDL_WINDOWEVENT:850 *strm = find_stream(sf, sevent.window.windowID, pevent);851 switch (sevent.window.event) {852 case SDL_WINDOWEVENT_RESIZED:853 pevent->type = PJMEDIA_EVENT_WND_RESIZED;854 pevent->data.wnd_resized.new_size.w =855 sevent.window.data1;856 pevent->data.wnd_resized.new_size.h =857 sevent.window.data2;858 break;859 case SDL_WINDOWEVENT_CLOSE:860 pevent->type = PJMEDIA_EVENT_WND_CLOSING;861 break;862 }863 break;864 #else /* SDL_VERSION_ATLEAST(1,3,0) */865 case SDL_VIDEORESIZE:866 pevent->type = PJMEDIA_EVENT_WND_RESIZED;867 pevent->data.wnd_resized.new_size.w = sevent.resize.w;868 pevent->data.wnd_resized.new_size.h = sevent.resize.h;869 break;870 case SDL_QUIT:871 pevent->type = PJMEDIA_EVENT_WND_CLOSING;872 break;873 #endif /* SDL_VERSION_ATLEAST(1,3,0) */874 }875 }876 877 return retval;878 }879 880 static struct sdl_stream* handle_event(struct sdl_factory *sf,881 struct sdl_stream *rcv_strm,882 pjmedia_event_type *ev_type)883 {884 struct sdl_stream *strm = NULL;885 pjmedia_event pevent;886 887 *ev_type = PJMEDIA_EVENT_NONE;888 while (poll_event(sf, &pevent, &strm)) {889 *ev_type = pevent.type;890 if (pevent.type != PJMEDIA_EVENT_NONE && strm &&891 (!rcv_strm || rcv_strm == strm))892 {893 pjmedia_event_publish(&strm->base.epub, &pevent);894 895 switch (pevent.type) {896 case PJMEDIA_EVENT_WND_RESIZED:897 strm->new_disp_size = &pevent.data.wnd_resized.new_size;898 strm->status = PJ_SUCCESS;899 detect_fmt_change(strm);900 if (strm->status != PJ_SUCCESS)901 return strm;902 break;903 904 case PJMEDIA_EVENT_WND_CLOSING:905 if (pevent.data.wnd_closing.cancel) {906 /* Cancel the closing operation */907 break;908 }909 910 /* Proceed to cleanup SDL. App must still call911 * pjmedia_dev_stream_destroy() when getting WND_CLOSED912 * event913 */914 strm->is_quitting = PJ_TRUE;915 sdl_stream_stop(&strm->base);916 917 return strm;918 default:919 /* Just to prevent gcc warning about unused enums */920 break;921 }922 }923 }924 925 return strm;926 }927 928 static int sdl_thread(void * data)929 {930 struct sdl_dev_t *sdl_dev = (struct sdl_dev_t *)data;931 struct sdl_factory *sf = sdl_dev->sf;932 struct sdl_stream *strm = sdl_dev->strm;933 934 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0935 NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];936 SDLDelegate *delegate = [[SDLDelegate alloc] init];937 #endif /* PJ_DARWINOS */938 939 #if SDL_VERSION_ATLEAST(1,3,0)940 # if defined(PJ_DARWINOS) && PJ_DARWINOS!=0941 [delegate performSelectorOnMainThread:@selector(sdl_init)942 withObject:nil waitUntilDone:YES];943 if (delegate->status != PJ_SUCCESS)944 goto on_error;945 # else /* PJ_DARWINOS */946 /* Initialize the SDL library */947 if (SDL_Init(SDL_INIT_VIDEO)) {948 sf->status = PJMEDIA_EVID_INIT;949 goto on_error;950 }951 # endif /* PJ_DARWINOS */952 #endif /* SDL_VERSION_ATLEAST(1,3,0) */953 sf->status = PJ_SUCCESS;954 955 while (!sf->is_quitting) {956 struct stream_list *it, *itBegin;957 pjmedia_event_type ev_type;958 struct sdl_stream *ev_stream;959 960 pj_mutex_lock(sf->mutex);961 962 if (!strm && pj_list_empty(&sf->streams)) {963 /* Wait until there is any stream. */964 pj_mutex_unlock(sf->mutex);965 pj_sem_wait(sf->sem);966 pj_mutex_lock(sf->mutex);967 }968 969 itBegin = &sf->streams;970 for (it = itBegin->next; it != itBegin; it = it->next) {971 if ((strm && it->stream != strm) || it->stream->is_quitting)972 continue;973 974 if (!it->stream->is_initialized) {975 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0976 delegate->strm = it->stream;977 [delegate performSelectorOnMainThread:@selector(sdl_create)978 withObject:nil waitUntilDone:YES];979 #else /* PJ_DARWINOS */980 sdl_create(it->stream);981 #endif /* PJ_DARWINOS */982 }983 984 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0985 delegate->strm = it->stream;986 [delegate performSelectorOnMainThread:@selector(detect_fmt_change)987 withObject:nil waitUntilDone:YES];988 [delegate performSelectorOnMainThread:@selector(put_frame)989 withObject:nil waitUntilDone:YES];990 #else /* PJ_DARWINOS */991 detect_fmt_change(it->stream);992 put_frame(it->stream, &it->stream->frame);993 #endif /* PJ_DARWINOS */994 }995 996 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0997 delegate->sf = sf;998 delegate->strm = strm;999 [delegate performSelectorOnMainThread:@selector(handle_event)1000 withObject:nil waitUntilDone:YES];1001 ev_stream = delegate->strm;1002 ev_type = delegate->ev_type;1003 #else /* PJ_DARWINOS */1004 ev_stream = handle_event(sf, strm, &ev_type);1005 #endif /* PJ_DARWINOS */1006 1007 itBegin = &sf->streams;1008 for (it = itBegin->next; it != itBegin; it = it->next) {1009 if ((strm && it->stream != strm) || !it->stream->is_quitting ||1010 it->stream->is_destroyed)1011 continue;1012 1013 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=01014 delegate->strm = it->stream;1015 [delegate performSelectorOnMainThread:@selector(sdl_destroy)1016 withObject:nil waitUntilDone:YES];1017 # if !(SDL_VERSION_ATLEAST(1,3,0))1018 [delegate performSelectorOnMainThread:@selector(sdl_quit)1019 withObject:nil waitUntilDone:YES];1020 # endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */1021 #else /* PJ_DARWINOS */1022 sdl_destroy(it->stream, PJ_TRUE);1023 # if !(SDL_VERSION_ATLEAST(1,3,0))1024 SDL_Quit();1025 # endif /* !(SDL_VERSION_ATLEAST(1,3,0)) */1026 #endif /* PJ_DARWINOS */1027 it->stream->screen = NULL;1028 it->stream->is_destroyed = PJ_TRUE;1029 1030 if (ev_type == PJMEDIA_EVENT_WND_CLOSING &&1031 it->stream == ev_stream)1032 {1033 pjmedia_event p_event;1034 1035 pjmedia_event_init(&p_event, PJMEDIA_EVENT_WND_CLOSED,1036 &it->stream->last_ts,1037 &it->stream->base.epub);1038 pjmedia_event_publish(&it->stream->base.epub, &p_event);1039 1040 /*1041 * Note: don't access the stream after this point, it1042 * might have been destroyed1043 */1044 }1045 1046 if (strm) {1047 pj_mutex_unlock(sf->mutex);1048 return 0;1049 }1050 }1051 1052 pj_mutex_unlock(sf->mutex);1053 }1054 1055 on_error:1056 #if SDL_VERSION_ATLEAST(1,3,0)1057 # if defined(PJ_DARWINOS) && PJ_DARWINOS!=01058 [delegate performSelectorOnMainThread:@selector(sdl_quit)1059 withObject:nil waitUntilDone:YES];1060 [delegate release];1061 [apool release];1062 # else /* PJ_DARWINOS */1063 SDL_Quit();1064 # endif /* PJ_DARWINOS */1065 #endif /* SDL_VERSION_ATLEAST(1,3,0) */1066 1067 return 0;1068 849 } 1069 850 … … 1073 854 { 1074 855 struct sdl_stream *stream = (struct sdl_stream*)strm; 856 pj_status_t status; 1075 857 1076 858 stream->last_ts.u64 = frame->timestamp.u64; 1077 859 1078 if (!stream->is_running) { 1079 stream->render_exited = PJ_TRUE; 1080 return PJ_SUCCESS; 1081 } 860 if (!stream->is_running) 861 return PJ_EINVALIDOP; 1082 862 1083 863 if (frame->size==0 || frame->buf==NULL || … … 1085 865 return PJ_SUCCESS; 1086 866 1087 pj_memcpy(stream->frame.buf, frame->buf, stream->vafp.framebytes); 1088 1089 return PJ_SUCCESS; 867 stream->frame = frame; 868 job_queue_post_job(stream->sf->jq, put_frame, strm, 0, &status); 869 870 return status; 1090 871 } 1091 872 … … 1105 886 PJ_ASSERT_RETURN(param->dir == PJMEDIA_DIR_RENDER, PJ_EINVAL); 1106 887 1107 #if !SDL_VERSION_ATLEAST(1,3,0)1108 /* Prior to 1.3, SDL does not support multiple renderers. */1109 pj_mutex_lock(sf->mutex);1110 if (!pj_list_empty(&sf->streams)) {1111 pj_mutex_unlock(sf->mutex);1112 return PJMEDIA_EVID_NOTREADY;1113 }1114 pj_mutex_unlock(sf->mutex);1115 #endif1116 1117 888 /* Create and Initialize stream descriptor */ 1118 889 pool = pj_pool_create(sf->pf, "sdl-dev", 1000, 1000, NULL); … … 1126 897 strm->user_data = user_data; 1127 898 pjmedia_event_publisher_init(&strm->base.epub, PJMEDIA_SIG_VID_DEV_SDL); 1128 pj_list_init(&strm->list_entry);1129 strm->list_entry.stream = strm;1130 899 1131 900 /* Create render stream here */ 1132 901 if (param->dir & PJMEDIA_DIR_RENDER) { 1133 struct sdl_dev_t sdl_dev; 1134 1135 strm->status = PJ_SUCCESS; 1136 sdl_dev.sf = strm->sf; 1137 sdl_dev.strm = strm; 1138 pj_mutex_lock(strm->sf->mutex); 1139 #if !SDL_USE_ONE_THREAD_PER_DISPLAY 1140 if (pj_list_empty(&strm->sf->streams)) 1141 pj_sem_post(strm->sf->sem); 1142 #endif /* !SDL_USE_ONE_THREAD_PER_DISPLAY */ 1143 pj_list_insert_after(&strm->sf->streams, &strm->list_entry); 1144 pj_mutex_unlock(strm->sf->mutex); 1145 1146 #if SDL_USE_ONE_THREAD_PER_DISPLAY 1147 status = pj_thread_create(pool, "sdl_thread", sdl_thread, 1148 &sdl_dev, 0, 0, &strm->sdl_thread); 902 job_queue_post_job(sf->jq, sdl_create, strm, 0, &status); 1149 903 if (status != PJ_SUCCESS) { 1150 904 goto on_error; 1151 905 } 1152 #endif /* SDL_USE_ONE_THREAD_PER_DISPLAY */ 1153 1154 while(strm->status == PJ_SUCCESS && !strm->surf && !strm->overlay 1155 #if SDL_VERSION_ATLEAST(1,3,0) 1156 && !strm->scr_tex 1157 #endif /* SDL_VERSION_ATLEAST(1,3,0) */ 1158 #if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 1159 && !strm->texture 1160 #endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */ 1161 ) 1162 { 1163 pj_thread_sleep(10); 1164 } 1165 if ((status = strm->status) != PJ_SUCCESS) { 1166 goto on_error; 1167 } 906 pj_list_init(&strm->list_entry); 907 strm->list_entry.stream = strm; 908 pj_mutex_lock(strm->sf->mutex); 909 if (pj_list_empty(&strm->sf->streams)) 910 pj_sem_post(strm->sf->sem); 911 pj_list_insert_after(&strm->sf->streams, &strm->list_entry); 912 pj_mutex_unlock(strm->sf->mutex); 1168 913 } 1169 914 … … 1174 919 ¶m->window_pos); 1175 920 } 1176 if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE) {1177 sdl_stream_set_cap(&strm->base,1178 PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE,1179 ¶m->window_hide);1180 }1181 921 1182 922 /* Done */ … … 1225 965 } 1226 966 1227 /* API: get capability */ 1228 static pj_status_t sdl_stream_get_cap(pjmedia_vid_dev_stream *s, 1229 pjmedia_vid_dev_cap cap, 1230 void *pval) 1231 { 1232 struct sdl_stream *strm = (struct sdl_stream*)s; 1233 1234 PJ_UNUSED_ARG(strm); 1235 1236 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL); 1237 1238 #if SDL_VERSION_ATLEAST(1,3,0) 967 struct strm_cap { 968 struct sdl_stream *strm; 969 pjmedia_vid_dev_cap cap; 970 union { 971 void *pval; 972 const void *cpval; 973 } pval; 974 }; 975 976 static pj_status_t get_cap(void *data) 977 { 978 struct strm_cap *scap = (struct strm_cap *)data; 979 struct sdl_stream *strm = scap->strm; 980 pjmedia_vid_dev_cap cap = scap->cap; 981 void *pval = scap->pval.pval; 982 1239 983 if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) 1240 984 { … … 1244 988 if (SDL_GetWindowWMInfo(strm->window, &info)) { 1245 989 pjmedia_vid_dev_hwnd *wnd = (pjmedia_vid_dev_hwnd *)pval; 1246 if ( info.subsystem == SDL_SYSWM_WINDOWS) {990 if (0) { } 1247 991 #if defined(SDL_VIDEO_DRIVER_WINDOWS) 992 else if (info.subsystem == SDL_SYSWM_WINDOWS) { 1248 993 wnd->type = PJMEDIA_VID_DEV_HWND_TYPE_WINDOWS; 1249 994 wnd->info.win.hwnd = (void *)info.info.win.window; 995 } 1250 996 #endif 1251 } else if (info.subsystem == SDL_SYSWM_X11) {1252 997 #if defined(SDL_VIDEO_DRIVER_X11) 998 else if (info.subsystem == SDL_SYSWM_X11) { 1253 999 wnd->info.x11.window = (void *)info.info.x11.window; 1254 1000 wnd->info.x11.display = (void *)info.info.x11.display; 1001 } 1255 1002 #endif 1256 } else if (info.subsystem == SDL_SYSWM_COCOA) {1257 1003 #if defined(SDL_VIDEO_DRIVER_COCOA) 1004 else if (info.subsystem == SDL_SYSWM_COCOA) { 1258 1005 wnd->info.cocoa.window = (void *)info.info.cocoa.window; 1006 } 1259 1007 #endif 1260 } else if (info.subsystem == SDL_SYSWM_UIKIT) {1261 1008 #if defined(SDL_VIDEO_DRIVER_UIKIT) 1009 else if (info.subsystem == SDL_SYSWM_UIKIT) { 1262 1010 wnd->info.ios.window = (void *)info.info.uikit.window; 1011 } 1263 1012 #endif 1013 else { 1014 return PJMEDIA_EVID_INVCAP; 1264 1015 } 1265 1016 return PJ_SUCCESS; … … 1279 1030 return PJ_SUCCESS; 1280 1031 } 1281 #else /* SDL_VERSION_ATLEAST(1,3,0) */1282 PJ_UNUSED_ARG(cap);1283 #endif /* SDL_VERSION_ATLEAST(1,3,0) */1284 1032 1285 1033 return PJMEDIA_EVID_INVCAP; 1286 1034 } 1287 1035 1288 /* API: set capability */1289 static pj_status_t sdl_stream_ set_cap(pjmedia_vid_dev_stream *s,1036 /* API: get capability */ 1037 static pj_status_t sdl_stream_get_cap(pjmedia_vid_dev_stream *s, 1290 1038 pjmedia_vid_dev_cap cap, 1291 constvoid *pval)1039 void *pval) 1292 1040 { 1293 1041 struct sdl_stream *strm = (struct sdl_stream*)s; 1294 1295 PJ_UNUSED_ARG(strm);1042 struct strm_cap scap; 1043 pj_status_t status; 1296 1044 1297 1045 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL); 1298 1046 1299 #if SDL_VERSION_ATLEAST(1,3,0) 1047 scap.strm = strm; 1048 scap.cap = cap; 1049 scap.pval.pval = pval; 1050 1051 job_queue_post_job(strm->sf->jq, get_cap, &scap, 0, &status); 1052 1053 return status; 1054 } 1055 1056 static pj_status_t set_cap(void *data) 1057 { 1058 struct strm_cap *scap = (struct strm_cap *)data; 1059 struct sdl_stream *strm = scap->strm; 1060 pjmedia_vid_dev_cap cap = scap->cap; 1061 const void *pval = scap->pval.cpval; 1062 1300 1063 if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION) { 1301 1064 SDL_SetWindowPosition(strm->window, ((pjmedia_coord *)pval)->x, … … 1308 1071 SDL_ShowWindow(strm->window); 1309 1072 return PJ_SUCCESS; 1310 } else 1311 #endif /* SDL_VERSION_ATLEAST(1,3,0) */ 1312 if (cap == PJMEDIA_VID_DEV_CAP_FORMAT) { 1313 strm->new_fmt = (pjmedia_format *)pval; 1314 while (strm->new_fmt) 1315 pj_thread_sleep(10); 1316 1317 if (strm->status != PJ_SUCCESS) { 1318 pj_status_t status = strm->status; 1073 } else if (cap == PJMEDIA_VID_DEV_CAP_FORMAT) { 1074 pj_status_t status; 1075 1076 status = change_format(strm, (pjmedia_format *)pval); 1077 if (status != PJ_SUCCESS) { 1078 pj_status_t status_; 1319 1079 1320 1080 /** … … 1322 1082 * to its original format. 1323 1083 */ 1324 strm->new_fmt = &strm->param.fmt; 1325 while (strm->new_fmt) 1326 pj_thread_sleep(10); 1327 1328 if (strm->status != PJ_SUCCESS) { 1084 status_ = change_format(strm, &strm->param.fmt); 1085 if (status_ != PJ_SUCCESS) { 1329 1086 /** 1330 1087 * This means that we failed to revert to our … … 1333 1090 status = PJMEDIA_EVID_ERR; 1334 1091 } 1335 1336 strm->status = status;1337 1092 } 1338 1093 1339 return st rm->status;1094 return status; 1340 1095 } else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE) { 1341 strm->new_disp_size = (pjmedia_rect_size *)pval; 1342 while (strm->new_disp_size) 1343 pj_thread_sleep(10); 1344 1345 return strm->status; 1096 pjmedia_rect_size *new_size = (pjmedia_rect_size *)pval; 1097 1098 SDL_SetWindowSize(strm->window, new_size->w, new_size->h); 1099 return resize_disp(strm, new_size); 1346 1100 } 1347 1101 1348 1102 return PJMEDIA_EVID_INVCAP; 1103 } 1104 1105 /* API: set capability */ 1106 static pj_status_t sdl_stream_set_cap(pjmedia_vid_dev_stream *s, 1107 pjmedia_vid_dev_cap cap, 1108 const void *pval) 1109 { 1110 struct sdl_stream *strm = (struct sdl_stream*)s; 1111 struct strm_cap scap; 1112 pj_status_t status; 1113 1114 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL); 1115 1116 scap.strm = strm; 1117 scap.cap = cap; 1118 scap.pval.cpval = pval; 1119 1120 job_queue_post_job(strm->sf->jq, set_cap, &scap, 0, &status); 1121 1122 return status; 1349 1123 } 1350 1124 … … 1357 1131 1358 1132 stream->is_running = PJ_TRUE; 1359 stream->render_exited = PJ_FALSE; 1360 1361 return PJ_SUCCESS; 1362 } 1133 1134 return PJ_SUCCESS; 1135 } 1136 1363 1137 1364 1138 /* API: Stop stream. */ … … 1366 1140 { 1367 1141 struct sdl_stream *stream = (struct sdl_stream*)strm; 1368 unsigned i;1369 1142 1370 1143 PJ_LOG(4, (THIS_FILE, "Stopping sdl video stream")); 1371 1144 1372 /* Wait for renderer put_frame() to finish */1373 1145 stream->is_running = PJ_FALSE; 1374 for (i=0; !stream->render_exited && i<50; ++i)1375 pj_thread_sleep(10);1376 1146 1377 1147 return PJ_SUCCESS; … … 1383 1153 { 1384 1154 struct sdl_stream *stream = (struct sdl_stream*)strm; 1155 pj_status_t status; 1385 1156 1386 1157 PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); … … 1388 1159 sdl_stream_stop(strm); 1389 1160 1390 if (!stream->is_quitting) { 1391 stream->is_quitting = PJ_TRUE; 1392 if (stream->sdl_thread) 1393 pj_thread_join(stream->sdl_thread); 1394 while (!stream->is_destroyed) { 1395 pj_thread_sleep(10); 1396 } 1397 } 1161 job_queue_post_job(stream->sf->jq, sdl_destroy_all, strm, 0, &status); 1162 if (status != PJ_SUCCESS) 1163 return status; 1398 1164 1399 1165 pj_mutex_lock(stream->sf->mutex); … … 1407 1173 } 1408 1174 1175 /**************************************************************************** 1176 * Job queue implementation 1177 */ 1178 static int job_thread(void * data) 1179 { 1180 job_queue *jq = (job_queue *)data; 1181 1182 while (1) { 1183 job *jb; 1184 1185 /* Wait until there is a job. */ 1186 pj_sem_wait(jq->sem); 1187 1188 /* Make sure there is no pending jobs before we quit. */ 1189 if (jq->is_quitting && jq->head == jq->tail && !jq->is_full) 1190 break; 1191 1192 jb = jq->jobs[jq->head]; 1193 jb->retval = (*jb->func)(jb->data); 1194 pj_sem_post(jq->job_sem[jq->head]); 1195 pj_mutex_lock(jq->mutex); 1196 jq->head = (jq->head + 1) % MAX_JOBS; 1197 jq->is_full = PJ_FALSE; 1198 pj_mutex_unlock(jq->mutex); 1199 } 1200 1201 return 0; 1202 } 1203 1204 static pj_status_t job_queue_create(pj_pool_t *pool, job_queue **pjq) 1205 { 1206 unsigned i; 1207 pj_status_t status; 1208 1209 job_queue *jq = PJ_POOL_ZALLOC_T(pool, job_queue); 1210 pj_sem_create(pool, "thread_sem", 0, MAX_JOBS + 1, &jq->sem); 1211 1409 1212 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 1410 @implementation SDLDelegate 1411 - (void)sdl_init 1412 { 1413 if (SDL_Init(SDL_INIT_VIDEO)) { 1414 PJ_LOG(4, (THIS_FILE, "Cannot initialize SDL")); 1415 status = PJMEDIA_EVID_INIT; 1416 } 1417 status = PJ_SUCCESS; 1418 } 1419 1420 - (void)sdl_quit 1421 { 1422 SDL_Quit(); 1423 } 1424 1425 - (void)detect_fmt_change 1426 { 1427 detect_fmt_change(strm); 1428 } 1429 1430 - (void)sdl_create 1431 { 1432 sdl_create(strm); 1433 } 1434 1435 - (void)sdl_destroy 1436 { 1437 sdl_destroy(strm, PJ_TRUE); 1438 } 1439 1440 - (void)handle_event 1441 { 1442 strm = handle_event(sf, strm, &ev_type); 1443 } 1444 1445 - (void)put_frame 1446 { 1447 put_frame(strm, &strm->frame); 1448 } 1449 1450 @end 1213 PJ_UNUSED_ARG(status); 1214 #else 1215 status = pj_thread_create(pool, "job_th", job_thread, jq, 0, 0, 1216 &jq->thread); 1217 if (status != PJ_SUCCESS) { 1218 job_queue_destroy(jq); 1219 return status; 1220 } 1451 1221 #endif /* PJ_DARWINOS */ 1222 1223 for (i = 0; i < MAX_JOBS; i++) { 1224 pj_sem_create(pool, "job_sem", 0, 1, &jq->job_sem[i]); 1225 } 1226 pj_mutex_create_recursive(pool, "job_mutex", &jq->mutex); 1227 1228 *pjq = jq; 1229 return PJ_SUCCESS; 1230 } 1231 1232 static pj_status_t job_queue_post_job(job_queue *jq, job_func_ptr func, 1233 void *data, unsigned flags, 1234 pj_status_t *retval) 1235 { 1236 job jb; 1237 int tail; 1238 1239 if (jq->is_quitting) 1240 return PJ_EBUSY; 1241 1242 jb.func = func; 1243 jb.data = data; 1244 jb.flags = flags; 1245 1246 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 1247 PJ_UNUSED_ARG(tail); 1248 NSAutoreleasePool *apool = [[NSAutoreleasePool alloc]init]; 1249 JQDelegate *jqd = [[JQDelegate alloc]init]; 1250 jqd->pjob = &jb; 1251 [jqd performSelectorOnMainThread:@selector(run_job) 1252 withObject:nil waitUntilDone:YES]; 1253 [jqd release]; 1254 [apool release]; 1255 #else /* PJ_DARWINOS */ 1256 pj_mutex_lock(jq->mutex); 1257 if (jq->is_full) { 1258 /* Sorry, the queue is full! */ 1259 pj_mutex_unlock(jq->mutex); 1260 *retval = PJ_ETOOMANY; 1261 return PJ_ETOOMANY; 1262 } 1263 jq->jobs[jq->tail] = &jb; 1264 tail = jq->tail; 1265 jq->tail = (jq->tail + 1) % MAX_JOBS; 1266 if (jq->tail == jq->head) 1267 jq->is_full = PJ_TRUE; 1268 pj_mutex_unlock(jq->mutex); 1269 1270 pj_sem_post(jq->sem); 1271 /* Wait until our posted job is completed. */ 1272 pj_sem_wait(jq->job_sem[tail]); 1273 #endif /* PJ_DARWINOS */ 1274 1275 *retval = jb.retval; 1276 1277 return PJ_SUCCESS; 1278 } 1279 1280 static pj_status_t job_queue_destroy(job_queue *jq) 1281 { 1282 unsigned i; 1283 1284 jq->is_quitting = PJ_TRUE; 1285 1286 if (jq->thread) { 1287 pj_sem_post(jq->sem); 1288 pj_thread_join(jq->thread); 1289 } 1290 1291 if (jq->sem) { 1292 pj_sem_destroy(jq->sem); 1293 jq->sem = NULL; 1294 } 1295 for (i = 0; i < MAX_JOBS; i++) { 1296 pj_sem_destroy(jq->job_sem[i]); 1297 } 1298 pj_mutex_destroy(jq->mutex); 1299 1300 return PJ_SUCCESS; 1301 } 1452 1302 1453 1303 #ifdef _MSC_VER
Note: See TracChangeset
for help on using the changeset viewer.