blob: c356b6eabdf3ab98ca1a1bfd30c4194637b0e2e1 [file] [log] [blame]
Benny Prijonoc45d9512010-12-10 11:04:30 +00001/* $Id$ */
2/*
3 * Copyright (C) 2008-2010 Teluu Inc. (http://www.teluu.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pjmedia/converter.h>
20#include <pjmedia-videodev/videodev_imp.h>
21#include <pj/assert.h>
22#include <pj/log.h>
23#include <pj/os.h>
24
25#if PJMEDIA_VIDEO_DEV_HAS_SDL
26
27#include <SDL.h>
28
29#define THIS_FILE "sdl_dev.c"
30#define DEFAULT_CLOCK_RATE 90000
31#define DEFAULT_WIDTH 640
32#define DEFAULT_HEIGHT 480
33#define DEFAULT_FPS 25
34
35
36typedef struct sdl_fmt_info
37{
38 pjmedia_format_id fmt_id;
39 Uint32 sdl_format;
40 Uint32 Rmask;
41 Uint32 Gmask;
42 Uint32 Bmask;
43 Uint32 Amask;
44} sdl_fmt_info;
45
46static sdl_fmt_info sdl_fmts[] =
47{
48#if PJ_IS_BIG_ENDIAN
49 {PJMEDIA_FORMAT_RGBA, 0, 0xFF000000, 0xFF0000, 0xFF00, 0xFF} ,
50 {PJMEDIA_FORMAT_RGB24, 0, 0xFF0000, 0xFF00, 0xFF, 0} ,
51 {PJMEDIA_FORMAT_BGRA, 0, 0xFF00, 0xFF0000, 0xFF000000, 0xFF} ,
52#else
53 {PJMEDIA_FORMAT_RGBA, 0, 0xFF, 0xFF00, 0xFF0000, 0xFF000000} ,
54 {PJMEDIA_FORMAT_RGB24, 0, 0xFF, 0xFF00, 0xFF0000, 0} ,
55 {PJMEDIA_FORMAT_BGRA, 0, 0xFF0000, 0xFF00, 0xFF, 0xFF000000} ,
56#endif
57
58 {PJMEDIA_FORMAT_DIB , 0, 0xFF0000, 0xFF00, 0xFF, 0} ,
59
60 {PJMEDIA_FORMAT_YUY2, SDL_YUY2_OVERLAY, 0, 0, 0, 0} ,
61 {PJMEDIA_FORMAT_UYVY, SDL_UYVY_OVERLAY, 0, 0, 0, 0} ,
62 {PJMEDIA_FORMAT_YVYU, SDL_YVYU_OVERLAY, 0, 0, 0, 0} ,
63 {PJMEDIA_FORMAT_I420, SDL_IYUV_OVERLAY, 0, 0, 0, 0} ,
64 {PJMEDIA_FORMAT_YV12, SDL_YV12_OVERLAY, 0, 0, 0, 0} ,
65 {PJMEDIA_FORMAT_I420JPEG, SDL_IYUV_OVERLAY, 0, 0, 0, 0} ,
66 {PJMEDIA_FORMAT_I422JPEG, SDL_YV12_OVERLAY, 0, 0, 0, 0} ,
67};
68
69/* sdl_ device info */
70struct sdl_dev_info
71{
72 pjmedia_vid_dev_info info;
73};
74
75/* sdl_ factory */
76struct sdl_factory
77{
78 pjmedia_vid_dev_factory base;
79 pj_pool_t *pool;
80 pj_pool_factory *pf;
81
82 unsigned dev_count;
83 struct sdl_dev_info *dev_info;
84};
85
86/* Video stream. */
87struct sdl_stream
88{
89 pjmedia_vid_stream base; /**< Base stream */
90 pjmedia_vid_param param; /**< Settings */
91 pj_pool_t *pool; /**< Memory pool. */
92
93 pjmedia_vid_cb vid_cb; /**< Stream callback. */
94 void *user_data; /**< Application data. */
95
96 pj_thread_t *sdl_thread; /**< SDL thread. */
97 pj_bool_t is_quitting;
98 pj_bool_t is_running;
99 pj_bool_t render_exited;
100 pj_status_t status;
101
102 SDL_Rect rect; /**< Display rectangle. */
103 SDL_Surface *screen; /**< Display screen. */
104 SDL_Surface *surf; /**< RGB surface. */
105 SDL_Overlay *overlay; /**< YUV overlay. */
106
107 /* For frame conversion */
108 pjmedia_converter *conv;
109 pjmedia_conversion_param conv_param;
110 pjmedia_frame conv_buf;
111
112 pjmedia_video_apply_fmt_param vafp;
113};
114
115
116/* Prototypes */
117static pj_status_t sdl_factory_init(pjmedia_vid_dev_factory *f);
118static pj_status_t sdl_factory_destroy(pjmedia_vid_dev_factory *f);
119static unsigned sdl_factory_get_dev_count(pjmedia_vid_dev_factory *f);
120static pj_status_t sdl_factory_get_dev_info(pjmedia_vid_dev_factory *f,
121 unsigned index,
122 pjmedia_vid_dev_info *info);
123static pj_status_t sdl_factory_default_param(pj_pool_t *pool,
124 pjmedia_vid_dev_factory *f,
125 unsigned index,
126 pjmedia_vid_param *param);
127static pj_status_t sdl_factory_create_stream(pjmedia_vid_dev_factory *f,
128 const pjmedia_vid_param *param,
129 const pjmedia_vid_cb *cb,
130 void *user_data,
131 pjmedia_vid_stream **p_vid_strm);
132
133static pj_status_t sdl_stream_get_param(pjmedia_vid_stream *strm,
134 pjmedia_vid_param *param);
135static pj_status_t sdl_stream_get_cap(pjmedia_vid_stream *strm,
136 pjmedia_vid_dev_cap cap,
137 void *value);
138static pj_status_t sdl_stream_set_cap(pjmedia_vid_stream *strm,
139 pjmedia_vid_dev_cap cap,
140 const void *value);
141static pj_status_t sdl_stream_put_frame(pjmedia_vid_stream *strm,
142 const pjmedia_frame *frame);
143static pj_status_t sdl_stream_start(pjmedia_vid_stream *strm);
144static pj_status_t sdl_stream_stop(pjmedia_vid_stream *strm);
145static pj_status_t sdl_stream_destroy(pjmedia_vid_stream *strm);
146
147/* Operations */
148static pjmedia_vid_dev_factory_op factory_op =
149{
150 &sdl_factory_init,
151 &sdl_factory_destroy,
152 &sdl_factory_get_dev_count,
153 &sdl_factory_get_dev_info,
154 &sdl_factory_default_param,
155 &sdl_factory_create_stream
156};
157
158static pjmedia_vid_stream_op stream_op =
159{
160 &sdl_stream_get_param,
161 &sdl_stream_get_cap,
162 &sdl_stream_set_cap,
163 &sdl_stream_start,
164 NULL,
165 &sdl_stream_put_frame,
166 &sdl_stream_stop,
167 &sdl_stream_destroy
168};
169
170
171/****************************************************************************
172 * Factory operations
173 */
174/*
175 * Init sdl_ video driver.
176 */
177pjmedia_vid_dev_factory* pjmedia_sdl_factory(pj_pool_factory *pf)
178{
179 struct sdl_factory *f;
180 pj_pool_t *pool;
181
182 pool = pj_pool_create(pf, "sdl video", 1000, 1000, NULL);
183 f = PJ_POOL_ZALLOC_T(pool, struct sdl_factory);
184 f->pf = pf;
185 f->pool = pool;
186 f->base.op = &factory_op;
187
188 return &f->base;
189}
190
191
192/* API: init factory */
193static pj_status_t sdl_factory_init(pjmedia_vid_dev_factory *f)
194{
195 struct sdl_factory *sf = (struct sdl_factory*)f;
196 struct sdl_dev_info *ddi;
197 unsigned i;
198
199 sf->dev_count = 1;
200 sf->dev_info = (struct sdl_dev_info*)
201 pj_pool_calloc(sf->pool, sf->dev_count,
202 sizeof(struct sdl_dev_info));
203
204 ddi = &sf->dev_info[0];
205 pj_bzero(ddi, sizeof(*ddi));
206 strncpy(ddi->info.name, "SDL renderer", sizeof(ddi->info.name));
207 ddi->info.name[sizeof(ddi->info.name)-1] = '\0';
208 strncpy(ddi->info.driver, "SDL", sizeof(ddi->info.driver));
209 ddi->info.driver[sizeof(ddi->info.driver)-1] = '\0';
210 ddi->info.dir = PJMEDIA_DIR_RENDER;
211 ddi->info.has_callback = PJ_FALSE;
212 ddi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT |
213 PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE;
214
215 ddi->info.fmt_cnt = PJ_ARRAY_SIZE(sdl_fmts);
216 ddi->info.fmt = (pjmedia_format*)
217 pj_pool_calloc(sf->pool, ddi->info.fmt_cnt,
218 sizeof(pjmedia_format));
219 for (i = 0; i < ddi->info.fmt_cnt; i++) {
220 pjmedia_format *fmt = &ddi->info.fmt[i];
221 pjmedia_format_init_video(fmt, sdl_fmts[i].fmt_id,
222 DEFAULT_WIDTH, DEFAULT_HEIGHT,
223 DEFAULT_FPS, 1);
224 }
225
226 PJ_LOG(4, (THIS_FILE, "SDL initialized"));
227
228 return PJ_SUCCESS;
229}
230
231/* API: destroy factory */
232static pj_status_t sdl_factory_destroy(pjmedia_vid_dev_factory *f)
233{
234 struct sdl_factory *sf = (struct sdl_factory*)f;
235 pj_pool_t *pool = sf->pool;
236
237 sf->pool = NULL;
238 pj_pool_release(pool);
239
240 return PJ_SUCCESS;
241}
242
243/* API: get number of devices */
244static unsigned sdl_factory_get_dev_count(pjmedia_vid_dev_factory *f)
245{
246 struct sdl_factory *sf = (struct sdl_factory*)f;
247 return sf->dev_count;
248}
249
250/* API: get device info */
251static pj_status_t sdl_factory_get_dev_info(pjmedia_vid_dev_factory *f,
252 unsigned index,
253 pjmedia_vid_dev_info *info)
254{
255 struct sdl_factory *sf = (struct sdl_factory*)f;
256
257 PJ_ASSERT_RETURN(index < sf->dev_count, PJMEDIA_EVID_INVDEV);
258
259 pj_memcpy(info, &sf->dev_info[index].info, sizeof(*info));
260
261 return PJ_SUCCESS;
262}
263
264/* API: create default device parameter */
265static pj_status_t sdl_factory_default_param(pj_pool_t *pool,
266 pjmedia_vid_dev_factory *f,
267 unsigned index,
268 pjmedia_vid_param *param)
269{
270 struct sdl_factory *sf = (struct sdl_factory*)f;
271 struct sdl_dev_info *di = &sf->dev_info[index];
272
273 PJ_ASSERT_RETURN(index < sf->dev_count, PJMEDIA_EVID_INVDEV);
274
275 PJ_UNUSED_ARG(pool);
276
277 pj_bzero(param, sizeof(*param));
278 if (di->info.dir & PJMEDIA_DIR_CAPTURE_RENDER) {
279 param->dir = PJMEDIA_DIR_CAPTURE_RENDER;
280 param->cap_id = index;
281 param->rend_id = index;
282 } else if (di->info.dir & PJMEDIA_DIR_CAPTURE) {
283 param->dir = PJMEDIA_DIR_CAPTURE;
284 param->cap_id = index;
285 param->rend_id = PJMEDIA_VID_INVALID_DEV;
286 } else if (di->info.dir & PJMEDIA_DIR_RENDER) {
287 param->dir = PJMEDIA_DIR_RENDER;
288 param->rend_id = index;
289 param->cap_id = PJMEDIA_VID_INVALID_DEV;
290 } else {
291 return PJMEDIA_EVID_INVDEV;
292 }
293
294 /* Set the device capabilities here */
295 param->flags = PJMEDIA_VID_DEV_CAP_FORMAT;
296 param->fmt.type = PJMEDIA_TYPE_VIDEO;
297 param->clock_rate = DEFAULT_CLOCK_RATE;
298 param->frame_rate.num = DEFAULT_FPS;
299 param->frame_rate.denum = 1;
300 pjmedia_format_init_video(&param->fmt, sdl_fmts[0].fmt_id,
301 DEFAULT_WIDTH, DEFAULT_HEIGHT,
302 DEFAULT_FPS, 1);
303
304 return PJ_SUCCESS;
305}
306
307static sdl_fmt_info* get_sdl_format_info(pjmedia_format_id id)
308{
309 unsigned i;
310
311 for (i = 0; i < sizeof(sdl_fmts)/sizeof(sdl_fmts[0]); i++) {
312 if (sdl_fmts[i].fmt_id == id)
313 return &sdl_fmts[i];
314 }
315
316 return NULL;
317}
318
319static int create_sdl_thread(void * data)
320{
321 struct sdl_stream *strm = (struct sdl_stream*)data;
322 sdl_fmt_info *sdl_info = get_sdl_format_info(strm->param.fmt.id);
323 const pjmedia_video_format_info *vfi;
324 pjmedia_video_format_detail *vfd;
325
326 vfi = pjmedia_get_video_format_info(pjmedia_video_format_mgr_instance(),
327 strm->param.fmt.id);
328 if (!vfi || !sdl_info) {
329 strm->status = PJMEDIA_EVID_BADFORMAT;
330 return strm->status;
331 }
332
333 strm->vafp.size = strm->param.fmt.det.vid.size;
334 strm->vafp.buffer = NULL;
335 if (vfi->apply_fmt(vfi, &strm->vafp) != PJ_SUCCESS) {
336 strm->status = PJMEDIA_EVID_BADFORMAT;
337 return strm->status;
338 }
339
340 /* Initialize the SDL library */
341 if (SDL_Init(SDL_INIT_VIDEO)) {
342 PJ_LOG(4, (THIS_FILE, "Cannot initialize SDL"));
343 strm->status = PJMEDIA_EVID_INIT;
344 return strm->status;
345 }
346
347 vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, PJ_TRUE);
348 strm->rect.x = strm->rect.y = 0;
349 strm->rect.w = (Uint16)vfd->size.w;
350 strm->rect.h = (Uint16)vfd->size.h;
351
352 /* Initialize the display, requesting a software surface */
353 strm->screen = SDL_SetVideoMode(strm->rect.w, strm->rect.h,
354 0, SDL_RESIZABLE | SDL_SWSURFACE);
355 if (strm->screen == NULL) {
356 strm->status = PJMEDIA_EVID_SYSERR;
357 return strm->status;
358 }
359 SDL_WM_SetCaption("pjmedia-SDL video", NULL);
360
361 if (vfi->color_model == PJMEDIA_COLOR_MODEL_RGB) {
362 strm->surf = SDL_CreateRGBSurface(SDL_SWSURFACE,
363 strm->rect.w, strm->rect.h,
364 vfi->bpp,
365 sdl_info->Rmask,
366 sdl_info->Gmask,
367 sdl_info->Bmask,
368 sdl_info->Amask);
369 if (strm->surf == NULL) {
370 strm->status = PJMEDIA_EVID_SYSERR;
371 return strm->status;
372 }
373 } else if (vfi->color_model == PJMEDIA_COLOR_MODEL_YUV) {
374 strm->overlay = SDL_CreateYUVOverlay(strm->rect.w, strm->rect.h,
375 sdl_info->sdl_format,
376 strm->screen);
377 if (strm->overlay == NULL) {
378 strm->status = PJMEDIA_EVID_SYSERR;
379 return strm->status;
380 }
381 }
382
383 while(!strm->is_quitting) {
384 SDL_Event sevent;
385 pjmedia_vid_event pevent;
386
387 while (SDL_WaitEvent(&sevent)) {
388 pj_bzero(&pevent, sizeof(pevent));
389
390 switch(sevent.type) {
391 case SDL_USEREVENT:
392 return 0;
393 case SDL_MOUSEBUTTONDOWN:
394 pevent.event_type = PJMEDIA_EVENT_MOUSEBUTTONDOWN;
395 if (strm->vid_cb.on_event_cb)
396 if ((*strm->vid_cb.on_event_cb)(&strm->base,
397 strm->user_data,
398 &pevent) != PJ_SUCCESS)
399 {
400 /* Application wants us to ignore this event */
401 break;
402 }
403 if (strm->is_running)
404 pjmedia_vid_stream_stop(&strm->base);
405 else
406 pjmedia_vid_stream_start(&strm->base);
407 break;
408 case SDL_VIDEORESIZE:
409 pevent.event_type = PJMEDIA_EVENT_WINDOW_RESIZE;
410 if (strm->vid_cb.on_event_cb)
411 if ((*strm->vid_cb.on_event_cb)(&strm->base,
412 strm->user_data,
413 &pevent) != PJ_SUCCESS)
414 {
415 /* Application wants us to ignore this event */
416 break;
417 }
418 /* TODO: move this to OUTPUT_RESIZE cap
419 strm->screen = SDL_SetVideoMode(sevent.resize.w,
420 sevent.resize.h,
421 0, SDL_RESIZABLE |
422 SDL_SWSURFACE);
423 */
424 break;
425 case SDL_QUIT:
426 pevent.event_type = PJMEDIA_EVENT_WINDOW_CLOSE;
427 /**
428 * To process PJMEDIA_EVENT_WINDOW_CLOSE event,
429 * application should do this in the on_event_cb callback:
430 * 1. stop further calls to #pjmedia_vid_stream_put_frame()
431 * 2. return PJ_SUCCESS
432 * Upon returning from the callback, SDL will destroy its
433 * own stream.
434 *
435 * Returning non-PJ_SUCCESS will cause SDL to ignore
436 * the event
437 */
438 if (strm->vid_cb.on_event_cb) {
439 strm->is_quitting = PJ_TRUE;
440 if ((*strm->vid_cb.on_event_cb)(&strm->base,
441 strm->user_data,
442 &pevent) != PJ_SUCCESS)
443 {
444 /* Application wants us to ignore this event */
445 strm->is_quitting = PJ_FALSE;
446 break;
447 }
448
449 /* Destroy the stream */
450 sdl_stream_destroy(&strm->base);
451 return 0;
452 }
453
454 /**
455 * Default event-handler when there is no user-specified
456 * callback: close the renderer window. We cannot destroy
457 * the stream here since there is no callback to notify
458 * the application.
459 */
460 sdl_stream_stop(&strm->base);
461 SDL_Quit();
462 strm->screen = NULL;
463 return 0;
464 default:
465 break;
466 }
467 }
468
469 }
470
471 return 0;
472}
473
474/* API: create stream */
475static pj_status_t sdl_factory_create_stream(pjmedia_vid_dev_factory *f,
476 const pjmedia_vid_param *param,
477 const pjmedia_vid_cb *cb,
478 void *user_data,
479 pjmedia_vid_stream **p_vid_strm)
480{
481 struct sdl_factory *sf = (struct sdl_factory*)f;
482 pj_pool_t *pool;
483 struct sdl_stream *strm;
484 pj_status_t status;
485
486 /* Create and Initialize stream descriptor */
487 pool = pj_pool_create(sf->pf, "sdl-dev", 1000, 1000, NULL);
488 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
489
490 strm = PJ_POOL_ZALLOC_T(pool, struct sdl_stream);
491 pj_memcpy(&strm->param, param, sizeof(*param));
492 strm->pool = pool;
493 pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
494 strm->user_data = user_data;
495
496 /* Create capture stream here */
497 if (param->dir & PJMEDIA_DIR_CAPTURE) {
498 }
499
500 /* Create render stream here */
501 if (param->dir & PJMEDIA_DIR_RENDER) {
502 strm->status = PJ_SUCCESS;
503 status = pj_thread_create(pool, "sdl_thread", create_sdl_thread,
504 strm, 0, 0, &strm->sdl_thread);
505 if (status != PJ_SUCCESS) {
506 goto on_error;
507 }
508 while (strm->status == PJ_SUCCESS && !strm->surf && !strm->overlay)
509 pj_thread_sleep(10);
510 if ((status = strm->status) != PJ_SUCCESS) {
511 goto on_error;
512 }
513
514 pjmedia_format_copy(&strm->conv_param.src, &param->fmt);
515 pjmedia_format_copy(&strm->conv_param.dst, &param->fmt);
516
517 status = pjmedia_converter_create(NULL, pool, &strm->conv_param,
518 &strm->conv);
519 }
520
521 /* Apply the remaining settings */
522 if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) {
523 sdl_stream_set_cap(&strm->base,
524 PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW,
525 &param->window);
526 }
527
528 /* Done */
529 strm->base.op = &stream_op;
530 *p_vid_strm = &strm->base;
531
532 return PJ_SUCCESS;
533
534on_error:
535 sdl_stream_destroy(&strm->base);
536 return status;
537}
538
539/* API: Get stream info. */
540static pj_status_t sdl_stream_get_param(pjmedia_vid_stream *s,
541 pjmedia_vid_param *pi)
542{
543 struct sdl_stream *strm = (struct sdl_stream*)s;
544
545 PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
546
547 pj_memcpy(pi, &strm->param, sizeof(*pi));
548
549/* if (sdl_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW,
550 &pi->fmt.info_size) == PJ_SUCCESS)
551 {
552 pi->flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW;
553 }
554*/
555 return PJ_SUCCESS;
556}
557
558/* API: get capability */
559static pj_status_t sdl_stream_get_cap(pjmedia_vid_stream *s,
560 pjmedia_vid_dev_cap cap,
561 void *pval)
562{
563 struct sdl_stream *strm = (struct sdl_stream*)s;
564
565 PJ_UNUSED_ARG(strm);
566
567 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
568
569 if (cap==PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW)
570 {
571 return PJ_SUCCESS;
572 } else {
573 return PJMEDIA_EVID_INVCAP;
574 }
575}
576
577/* API: set capability */
578static pj_status_t sdl_stream_set_cap(pjmedia_vid_stream *s,
579 pjmedia_vid_dev_cap cap,
580 const void *pval)
581{
582 struct sdl_stream *strm = (struct sdl_stream*)s;
583
584 PJ_UNUSED_ARG(strm);
585
586 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
587
588 if (cap==PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW)
589 {
590 return PJ_SUCCESS;
591 }
592
593 return PJMEDIA_EVID_INVCAP;
594}
595
596/* API: Put frame from stream */
597static pj_status_t sdl_stream_put_frame(pjmedia_vid_stream *strm,
598 const pjmedia_frame *frame)
599{
600 struct sdl_stream *stream = (struct sdl_stream*)strm;
601
602 if (!stream->is_running) {
603 stream->render_exited = PJ_TRUE;
604 return PJ_SUCCESS;
605 }
606
607 if (stream->surf) {
608 if (SDL_MUSTLOCK(stream->surf)) {
609 if (SDL_LockSurface(stream->surf) < 0) {
610 PJ_LOG(3, (THIS_FILE, "Unable to lock SDL surface"));
611 return PJMEDIA_EVID_NOTREADY;
612 }
613 }
614
615 pj_memcpy(stream->surf->pixels, frame->buf, frame->size);
616
617 if (SDL_MUSTLOCK(stream->surf)) {
618 SDL_UnlockSurface(stream->surf);
619 }
620 SDL_BlitSurface(stream->surf, NULL, stream->screen, NULL);
621 SDL_UpdateRect(stream->screen, 0, 0, 0, 0);
622 } else if (stream->overlay) {
623 int i, sz, offset;
624
625 if (SDL_LockYUVOverlay(stream->overlay) < 0) {
626 PJ_LOG(3, (THIS_FILE, "Unable to lock SDL overlay"));
627 return PJMEDIA_EVID_NOTREADY;
628 }
629
630 for (i = 0, offset = 0; i < stream->overlay->planes; i++) {
631 sz = stream->vafp.plane_bytes[i];
632 pj_memcpy(stream->overlay->pixels[i],
633 (char *)frame->buf + offset, sz);
634 offset += sz;
635 }
636
637 SDL_UnlockYUVOverlay(stream->overlay);
638 SDL_DisplayYUVOverlay(stream->overlay, &stream->rect);
639 }
640
641 return PJ_SUCCESS;
642}
643
644/* API: Start stream. */
645static pj_status_t sdl_stream_start(pjmedia_vid_stream *strm)
646{
647 struct sdl_stream *stream = (struct sdl_stream*)strm;
648
649 PJ_LOG(4, (THIS_FILE, "Starting sdl video stream"));
650
651 stream->is_running = PJ_TRUE;
652 stream->render_exited = PJ_FALSE;
653
654 return PJ_SUCCESS;
655}
656
657/* API: Stop stream. */
658static pj_status_t sdl_stream_stop(pjmedia_vid_stream *strm)
659{
660 struct sdl_stream *stream = (struct sdl_stream*)strm;
661 unsigned i;
662
663 PJ_LOG(4, (THIS_FILE, "Stopping sdl video stream"));
664
665 /* Wait for renderer put_frame() to finish */
666 stream->is_running = PJ_FALSE;
667 for (i=0; !stream->render_exited && i<100; ++i)
668 pj_thread_sleep(10);
669
670 return PJ_SUCCESS;
671}
672
673
674/* API: Destroy stream. */
675static pj_status_t sdl_stream_destroy(pjmedia_vid_stream *strm)
676{
677 struct sdl_stream *stream = (struct sdl_stream*)strm;
678 SDL_Event sevent;
679
680 PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
681
682 if (!stream->is_quitting) {
683 sevent.type = SDL_USEREVENT;
684 SDL_PushEvent(&sevent);
685 pj_thread_join(stream->sdl_thread);
686 }
687
688 sdl_stream_stop(strm);
689
690 if (stream->surf) {
691 SDL_FreeSurface(stream->surf);
692 stream->surf = NULL;
693 }
694
695 if (stream->overlay) {
696 SDL_FreeYUVOverlay(stream->overlay);
697 stream->overlay = NULL;
698 }
699
700 SDL_Quit();
701 stream->screen = NULL;
702
703 pj_pool_release(stream->pool);
704
705 return PJ_SUCCESS;
706}
707
Nanang Izzuddine43ee722010-12-10 20:55:13 +0000708#ifdef _MSC_VER
709# pragma comment( lib, "sdl.lib")
710#endif
711
Benny Prijonoc45d9512010-12-10 11:04:30 +0000712#endif /* PJMEDIA_VIDEO_DEV_HAS_SDL */