blob: 833608e83d29a33b7c70ad718f17a4308154a17b [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-videodev/videodev_imp.h>
20#include <pj/assert.h>
21#include <pj/errno.h>
22#include <pj/log.h>
23#include <pj/pool.h>
24#include <pj/string.h>
25
26#define THIS_FILE "videodev.c"
27
28#define DEFINE_CAP(name, info) {name, info}
29
30/* Capability names */
31static struct cap_info
32{
33 const char *name;
34 const char *info;
35} cap_infos[] =
36{
37 DEFINE_CAP("format", "Video format"),
38 DEFINE_CAP("scale", "Input dimension"),
39 DEFINE_CAP("window", "Renderer window"),
Sauw Mingcbd82af2011-06-30 09:31:05 +000040 DEFINE_CAP("resize", "Renderer resize"),
41 DEFINE_CAP("position", "Renderer position"),
42 DEFINE_CAP("hide", "Renderer hide"),
Benny Prijonoc45d9512010-12-10 11:04:30 +000043};
44
45
46/*
47 * The device index seen by application and driver is different.
48 *
49 * At application level, device index is index to global list of device.
50 * At driver level, device index is index to device list on that particular
51 * factory only.
52 */
53#define MAKE_DEV_ID(f_id, index) (((f_id & 0xFFFF) << 16) | (index & 0xFFFF))
54#define GET_INDEX(dev_id) ((dev_id) & 0xFFFF)
55#define GET_FID(dev_id) ((dev_id) >> 16)
56#define DEFAULT_DEV_ID 0
57
58
59/* extern functions to create factories */
60#if PJMEDIA_VIDEO_DEV_HAS_NULL_VIDEO
61pjmedia_vid_dev_factory* pjmedia_null_video_factory(pj_pool_factory *pf);
62#endif
63
64#if PJMEDIA_VIDEO_DEV_HAS_DSHOW
65pjmedia_vid_dev_factory* pjmedia_dshow_factory(pj_pool_factory *pf);
66#endif
67
68#if PJMEDIA_VIDEO_DEV_HAS_CBAR_SRC
69pjmedia_vid_dev_factory* pjmedia_cbar_factory(pj_pool_factory *pf);
70#endif
71
72#if PJMEDIA_VIDEO_DEV_HAS_SDL
73pjmedia_vid_dev_factory* pjmedia_sdl_factory(pj_pool_factory *pf);
74#endif
75
76#if PJMEDIA_VIDEO_DEV_HAS_FFMPEG
77pjmedia_vid_dev_factory* pjmedia_ffmpeg_factory(pj_pool_factory *pf);
78#endif
79
80#if PJMEDIA_VIDEO_DEV_HAS_V4L2
81pjmedia_vid_dev_factory* pjmedia_v4l2_factory(pj_pool_factory *pf);
82#endif
83
Sauw Ming6e6c2152010-12-14 13:03:10 +000084#if PJMEDIA_VIDEO_DEV_HAS_QT
85pjmedia_vid_dev_factory* pjmedia_qt_factory(pj_pool_factory *pf);
86#endif
87
88#if PJMEDIA_VIDEO_DEV_HAS_IOS
89pjmedia_vid_dev_factory* pjmedia_ios_factory(pj_pool_factory *pf);
90#endif
91
Benny Prijonoc45d9512010-12-10 11:04:30 +000092#define MAX_DRIVERS 16
93#define MAX_DEVS 64
94
95
96/* driver structure */
97struct driver
98{
99 /* Creation function */
100 pjmedia_vid_dev_factory_create_func_ptr create;
101 /* Factory instance */
102 pjmedia_vid_dev_factory *f;
103 char name[32]; /* Driver name */
104 unsigned dev_cnt; /* Number of devices */
105 unsigned start_idx; /* Start index in global list */
106 int cap_dev_idx; /* Default capture device. */
107 int rend_dev_idx; /* Default render device */
108};
109
Sauw Minge90ece82011-06-09 04:05:44 +0000110/* The video device subsystem */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000111static struct vid_subsys
112{
113 unsigned init_count; /* How many times init() is called */
114 pj_pool_factory *pf; /* The pool factory. */
115
116 unsigned drv_cnt; /* Number of drivers. */
117 struct driver drv[MAX_DRIVERS]; /* Array of drivers. */
118
119 unsigned dev_cnt; /* Total number of devices. */
120 pj_uint32_t dev_list[MAX_DEVS];/* Array of device IDs. */
121
122} vid_subsys;
123
124/* API: get capability name/info */
125PJ_DEF(const char*) pjmedia_vid_dev_cap_name(pjmedia_vid_dev_cap cap,
126 const char **p_desc)
127{
128 const char *desc;
129 unsigned i;
130
131 if (p_desc==NULL) p_desc = &desc;
132
133 for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {
134 if ((1 << i)==cap)
135 break;
136 }
137
Benny Prijono333eaf12011-07-07 07:44:44 +0000138 if (i==PJ_ARRAY_SIZE(cap_infos)) {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000139 *p_desc = "??";
140 return "??";
141 }
142
143 *p_desc = cap_infos[i].info;
144 return cap_infos[i].name;
145}
146
Sauw Ming5291a2d2011-07-15 07:52:44 +0000147static pj_status_t get_cap_pointer(const pjmedia_vid_dev_param *param,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000148 pjmedia_vid_dev_cap cap,
149 void **ptr,
150 unsigned *size)
151{
152#define FIELD_INFO(name) *ptr = (void*)&param->name; \
153 *size = sizeof(param->name)
154
155 switch (cap) {
156 case PJMEDIA_VID_DEV_CAP_FORMAT:
157 FIELD_INFO(fmt);
158 break;
159 case PJMEDIA_VID_DEV_CAP_INPUT_SCALE:
160 FIELD_INFO(disp_size);
161 break;
162 case PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW:
163 FIELD_INFO(window);
164 break;
Sauw Mingcbd82af2011-06-30 09:31:05 +0000165 case PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE:
166 FIELD_INFO(disp_size);
167 break;
168 case PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION:
169 FIELD_INFO(window_pos);
170 break;
171 case PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE:
172 FIELD_INFO(window_hide);
173 break;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000174 default:
175 return PJMEDIA_EVID_INVCAP;
176 }
177
178#undef FIELD_INFO
179
180 return PJ_SUCCESS;
181}
182
183/* API: set cap value to param */
Sauw Ming5291a2d2011-07-15 07:52:44 +0000184PJ_DEF(pj_status_t)
185pjmedia_vid_dev_param_set_cap( pjmedia_vid_dev_param *param,
186 pjmedia_vid_dev_cap cap,
187 const void *pval)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000188{
189 void *cap_ptr;
190 unsigned cap_size;
191 pj_status_t status;
192
193 status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
194 if (status != PJ_SUCCESS)
195 return status;
196
197 pj_memcpy(cap_ptr, pval, cap_size);
198 param->flags |= cap;
199
200 return PJ_SUCCESS;
201}
202
203/* API: get cap value from param */
Sauw Ming5291a2d2011-07-15 07:52:44 +0000204PJ_DEF(pj_status_t)
205pjmedia_vid_dev_param_get_cap( const pjmedia_vid_dev_param *param,
206 pjmedia_vid_dev_cap cap,
207 void *pval)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000208{
209 void *cap_ptr;
210 unsigned cap_size;
211 pj_status_t status;
212
213 status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
214 if (status != PJ_SUCCESS)
215 return status;
216
217 if ((param->flags & cap) == 0) {
218 pj_bzero(cap_ptr, cap_size);
219 return PJMEDIA_EVID_INVCAP;
220 }
221
222 pj_memcpy(pval, cap_ptr, cap_size);
223 return PJ_SUCCESS;
224}
225
226/* Internal: init driver */
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000227static pj_status_t init_driver(unsigned drv_idx, pj_bool_t refresh)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000228{
229 struct driver *drv = &vid_subsys.drv[drv_idx];
230 pjmedia_vid_dev_factory *f;
231 unsigned i, dev_cnt;
232 pj_status_t status;
233
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000234 if (!refresh) {
235 /* Create the factory */
236 f = (*drv->create)(vid_subsys.pf);
237 if (!f)
238 return PJ_EUNKNOWN;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000239
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000240 /* Call factory->init() */
241 status = f->op->init(f);
242 if (status != PJ_SUCCESS) {
243 f->op->destroy(f);
244 return status;
245 }
246 } else {
247 f = drv->f;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000248 }
249
250 /* Get number of devices */
251 dev_cnt = f->op->get_dev_count(f);
252 if (dev_cnt + vid_subsys.dev_cnt > MAX_DEVS) {
253 PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because"
254 " there are too many devices",
255 vid_subsys.dev_cnt + dev_cnt - MAX_DEVS));
256 dev_cnt = MAX_DEVS - vid_subsys.dev_cnt;
257 }
258
259 /* enabling this will cause pjsua-lib initialization to fail when there
260 * is no video device installed in the system, even when pjsua has been
261 * run with --null-video
262 *
263 if (dev_cnt == 0) {
264 f->op->destroy(f);
265 return PJMEDIA_EVID_NODEV;
266 }
267 */
268
269 /* Fill in default devices */
270 drv->rend_dev_idx = drv->cap_dev_idx = -1;
271 for (i=0; i<dev_cnt; ++i) {
272 pjmedia_vid_dev_info info;
273
274 status = f->op->get_dev_info(f, i, &info);
275 if (status != PJ_SUCCESS) {
276 f->op->destroy(f);
277 return status;
278 }
279
280 if (drv->name[0]=='\0') {
281 /* Set driver name */
282 pj_ansi_strncpy(drv->name, info.driver, sizeof(drv->name));
283 drv->name[sizeof(drv->name)-1] = '\0';
284 }
285
286 if (drv->rend_dev_idx < 0 && (info.dir & PJMEDIA_DIR_RENDER)) {
287 /* Set default render device */
288 drv->rend_dev_idx = i;
289 }
290 if (drv->cap_dev_idx < 0 && (info.dir & PJMEDIA_DIR_CAPTURE)) {
291 /* Set default capture device */
292 drv->cap_dev_idx = i;
293 }
294
295 if (drv->rend_dev_idx >= 0 && drv->cap_dev_idx >= 0) {
296 /* Done. */
297 break;
298 }
299 }
300
301 /* Register the factory */
302 drv->f = f;
303 drv->f->sys.drv_idx = drv_idx;
304 drv->start_idx = vid_subsys.dev_cnt;
305 drv->dev_cnt = dev_cnt;
306
307 /* Register devices to global list */
308 for (i=0; i<dev_cnt; ++i) {
309 vid_subsys.dev_list[vid_subsys.dev_cnt++] = MAKE_DEV_ID(drv_idx, i);
310 }
311
312 return PJ_SUCCESS;
313}
314
315/* Internal: deinit driver */
316static void deinit_driver(unsigned drv_idx)
317{
318 struct driver *drv = &vid_subsys.drv[drv_idx];
319
320 if (drv->f) {
321 drv->f->op->destroy(drv->f);
322 drv->f = NULL;
323 }
324
325 drv->dev_cnt = 0;
326 drv->rend_dev_idx = drv->cap_dev_idx = -1;
327}
328
Sauw Minge90ece82011-06-09 04:05:44 +0000329/* API: Initialize the video device subsystem. */
330PJ_DEF(pj_status_t) pjmedia_vid_dev_subsys_init(pj_pool_factory *pf)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000331{
332 unsigned i;
333 pj_status_t status = PJ_SUCCESS;
334
335 /* Allow init() to be called multiple times as long as there is matching
336 * number of shutdown().
337 */
338 if (vid_subsys.init_count++ != 0) {
339 return PJ_SUCCESS;
340 }
341
342 /* Register error subsystem */
343 pj_register_strerror(PJMEDIA_VIDEODEV_ERRNO_START,
344 PJ_ERRNO_SPACE_SIZE,
345 &pjmedia_videodev_strerror);
346
347 /* Init */
348 vid_subsys.pf = pf;
349 vid_subsys.drv_cnt = 0;
350 vid_subsys.dev_cnt = 0;
351
352 /* Register creation functions */
353#if PJMEDIA_VIDEO_DEV_HAS_V4L2
354 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_v4l2_factory;
355#endif
Sauw Ming6e6c2152010-12-14 13:03:10 +0000356#if PJMEDIA_VIDEO_DEV_HAS_QT
357 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_qt_factory;
358#endif
359#if PJMEDIA_VIDEO_DEV_HAS_IOS
360 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_ios_factory;
361#endif
Benny Prijonoc45d9512010-12-10 11:04:30 +0000362#if PJMEDIA_VIDEO_DEV_HAS_DSHOW
363 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_dshow_factory;
364#endif
365#if PJMEDIA_VIDEO_DEV_HAS_FFMPEG
366 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_ffmpeg_factory;
367#endif
368#if PJMEDIA_VIDEO_DEV_HAS_CBAR_SRC
369 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_cbar_factory;
370#endif
371#if PJMEDIA_VIDEO_DEV_HAS_SDL
372 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_sdl_factory;
373#endif
374
375 /* Initialize each factory and build the device ID list */
376 for (i=0; i<vid_subsys.drv_cnt; ++i) {
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000377 status = init_driver(i, PJ_FALSE);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000378 if (status != PJ_SUCCESS) {
379 deinit_driver(i);
380 continue;
381 }
382 }
383
384 return vid_subsys.dev_cnt ? PJ_SUCCESS : status;
385}
386
Sauw Minge90ece82011-06-09 04:05:44 +0000387/* API: register a video device factory to the video device subsystem. */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000388PJ_DEF(pj_status_t)
389pjmedia_vid_register_factory(pjmedia_vid_dev_factory_create_func_ptr adf)
390{
391 pj_status_t status;
392
393 if (vid_subsys.init_count == 0)
394 return PJMEDIA_EVID_INIT;
395
396 vid_subsys.drv[vid_subsys.drv_cnt].create = adf;
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000397 status = init_driver(vid_subsys.drv_cnt, PJ_FALSE);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000398 if (status == PJ_SUCCESS) {
399 vid_subsys.drv_cnt++;
400 } else {
401 deinit_driver(vid_subsys.drv_cnt);
402 }
403
404 return status;
405}
406
Sauw Minge90ece82011-06-09 04:05:44 +0000407/* API: unregister a video device factory from the video device subsystem. */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000408PJ_DEF(pj_status_t)
409pjmedia_vid_unregister_factory(pjmedia_vid_dev_factory_create_func_ptr adf)
410{
411 unsigned i, j;
412
413 if (vid_subsys.init_count == 0)
414 return PJMEDIA_EVID_INIT;
415
416 for (i=0; i<vid_subsys.drv_cnt; ++i) {
417 struct driver *drv = &vid_subsys.drv[i];
418
419 if (drv->create == adf) {
420 for (j = drv->start_idx; j < drv->start_idx + drv->dev_cnt; j++)
421 {
422 vid_subsys.dev_list[j] = (pj_uint32_t)PJMEDIA_VID_INVALID_DEV;
423 }
424
425 deinit_driver(i);
426 pj_bzero(drv, sizeof(*drv));
427 return PJ_SUCCESS;
428 }
429 }
430
431 return PJMEDIA_EVID_ERR;
432}
433
Sauw Minge90ece82011-06-09 04:05:44 +0000434/* API: get the pool factory registered to the video device subsystem. */
435PJ_DEF(pj_pool_factory*) pjmedia_vid_dev_subsys_get_pool_factory(void)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000436{
437 return vid_subsys.pf;
438}
439
Sauw Minge90ece82011-06-09 04:05:44 +0000440/* API: Shutdown the video device subsystem. */
441PJ_DEF(pj_status_t) pjmedia_vid_dev_subsys_shutdown(void)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000442{
443 unsigned i;
444
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000445 /* Allow shutdown() to be called multiple times as long as there is
446 * matching number of init().
Benny Prijonoc45d9512010-12-10 11:04:30 +0000447 */
448 if (vid_subsys.init_count == 0) {
449 return PJ_SUCCESS;
450 }
451 --vid_subsys.init_count;
452
Sauw Minge90ece82011-06-09 04:05:44 +0000453 if (vid_subsys.init_count == 0) {
454 for (i=0; i<vid_subsys.drv_cnt; ++i) {
455 deinit_driver(i);
456 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000457
Sauw Minge90ece82011-06-09 04:05:44 +0000458 vid_subsys.pf = NULL;
459 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000460 return PJ_SUCCESS;
461}
462
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000463/* API: Refresh the list of video devices installed in the system. */
464PJ_DEF(pj_status_t) pjmedia_vid_dev_refresh(void)
465{
466 unsigned i;
467
468 vid_subsys.dev_cnt = 0;
469 for (i=0; i<vid_subsys.drv_cnt; ++i) {
470 struct driver *drv = &vid_subsys.drv[i];
471
472 if (drv->f && drv->f->op->refresh) {
473 pj_status_t status = drv->f->op->refresh(drv->f);
474 if (status != PJ_SUCCESS) {
475 PJ_PERROR(4, (THIS_FILE, status, "Unable to refresh device "
476 "list for %s", drv->name));
477 }
478 }
479 init_driver(i, PJ_TRUE);
480 }
481 return PJ_SUCCESS;
482}
483
Benny Prijonoc45d9512010-12-10 11:04:30 +0000484/* API: Get the number of video devices installed in the system. */
485PJ_DEF(unsigned) pjmedia_vid_dev_count(void)
486{
487 return vid_subsys.dev_cnt;
488}
489
490/* Internal: convert local index to global device index */
491static pj_status_t make_global_index(unsigned drv_idx,
492 pjmedia_vid_dev_index *id)
493{
494 if (*id < 0) {
495 return PJ_SUCCESS;
496 }
497
498 /* Check that factory still exists */
499 PJ_ASSERT_RETURN(vid_subsys.drv[drv_idx].f, PJ_EBUG);
500
501 /* Check that device index is valid */
502 PJ_ASSERT_RETURN(*id>=0 && *id<(int)vid_subsys.drv[drv_idx].dev_cnt,
503 PJ_EBUG);
504
505 *id += vid_subsys.drv[drv_idx].start_idx;
506 return PJ_SUCCESS;
507}
508
509/* Internal: lookup device id */
510static pj_status_t lookup_dev(pjmedia_vid_dev_index id,
511 pjmedia_vid_dev_factory **p_f,
512 unsigned *p_local_index)
513{
514 int f_id, index;
515
516 if (id < 0) {
517 unsigned i;
518
Nanang Izzuddinbe321fd2011-07-15 02:33:17 +0000519 if (id <= PJMEDIA_VID_INVALID_DEV)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000520 return PJMEDIA_EVID_INVDEV;
521
522 for (i=0; i<vid_subsys.drv_cnt; ++i) {
523 struct driver *drv = &vid_subsys.drv[i];
524 if (id==PJMEDIA_VID_DEFAULT_CAPTURE_DEV &&
525 drv->cap_dev_idx >= 0)
526 {
527 id = drv->cap_dev_idx;
528 make_global_index(i, &id);
529 break;
530 } else if (id==PJMEDIA_VID_DEFAULT_RENDER_DEV &&
531 drv->rend_dev_idx >= 0)
532 {
533 id = drv->rend_dev_idx;
534 make_global_index(i, &id);
535 break;
536 }
537 }
538
539 if (id < 0) {
540 return PJMEDIA_EVID_NODEFDEV;
541 }
542 }
543
544 f_id = GET_FID(vid_subsys.dev_list[id]);
545 index = GET_INDEX(vid_subsys.dev_list[id]);
546
547 if (f_id < 0 || f_id >= (int)vid_subsys.drv_cnt)
548 return PJMEDIA_EVID_INVDEV;
549
550 if (index < 0 || index >= (int)vid_subsys.drv[f_id].dev_cnt)
551 return PJMEDIA_EVID_INVDEV;
552
553 *p_f = vid_subsys.drv[f_id].f;
554 *p_local_index = (unsigned)index;
555
556 return PJ_SUCCESS;
557
558}
559
560/* API: Get device information. */
561PJ_DEF(pj_status_t) pjmedia_vid_dev_get_info(pjmedia_vid_dev_index id,
562 pjmedia_vid_dev_info *info)
563{
564 pjmedia_vid_dev_factory *f;
565 unsigned index;
566 pj_status_t status;
567
Nanang Izzuddinbe321fd2011-07-15 02:33:17 +0000568 PJ_ASSERT_RETURN(info, PJ_EINVAL);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000569 PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
570
Nanang Izzuddinbe321fd2011-07-15 02:33:17 +0000571 if (id <= PJMEDIA_VID_INVALID_DEV)
572 return PJMEDIA_EVID_INVDEV;
573
Benny Prijonoc45d9512010-12-10 11:04:30 +0000574 status = lookup_dev(id, &f, &index);
575 if (status != PJ_SUCCESS)
576 return status;
577
Nanang Izzuddinf4ee4152011-07-12 03:20:36 +0000578 status = f->op->get_dev_info(f, index, info);
579
580 /* Make sure device ID is the real ID (not PJMEDIA_VID_DEFAULT_*_DEV) */
581 info->id = index;
Nanang Izzuddin32b924f2011-07-13 13:23:29 +0000582 make_global_index(f->sys.drv_idx, &info->id);
Nanang Izzuddinf4ee4152011-07-12 03:20:36 +0000583
584 return status;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000585}
586
587/* API: find device */
588PJ_DEF(pj_status_t) pjmedia_vid_dev_lookup( const char *drv_name,
589 const char *dev_name,
590 pjmedia_vid_dev_index *id)
591{
592 pjmedia_vid_dev_factory *f = NULL;
593 unsigned drv_idx, dev_idx;
594
595 PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);
596 PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
597
598 for (drv_idx=0; drv_idx<vid_subsys.drv_cnt; ++drv_idx) {
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000599 if (!pj_ansi_stricmp(drv_name, vid_subsys.drv[drv_idx].name))
600 {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000601 f = vid_subsys.drv[drv_idx].f;
602 break;
603 }
604 }
605
606 if (!f)
607 return PJ_ENOTFOUND;
608
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000609 for (dev_idx=0; dev_idx<vid_subsys.drv[drv_idx].dev_cnt; ++dev_idx)
610 {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000611 pjmedia_vid_dev_info info;
612 pj_status_t status;
613
614 status = f->op->get_dev_info(f, dev_idx, &info);
615 if (status != PJ_SUCCESS)
616 return status;
617
618 if (!pj_ansi_stricmp(dev_name, info.name))
619 break;
620 }
621
622 if (dev_idx==vid_subsys.drv[drv_idx].dev_cnt)
623 return PJ_ENOTFOUND;
624
625 *id = dev_idx;
626 make_global_index(drv_idx, id);
627
628 return PJ_SUCCESS;
629}
630
631/* API: Initialize the video device parameters with default values for the
632 * specified device.
633 */
634PJ_DEF(pj_status_t) pjmedia_vid_dev_default_param(pj_pool_t *pool,
635 pjmedia_vid_dev_index id,
Sauw Ming5291a2d2011-07-15 07:52:44 +0000636 pjmedia_vid_dev_param *param)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000637{
638 pjmedia_vid_dev_factory *f;
639 unsigned index;
640 pj_status_t status;
641
Nanang Izzuddinbe321fd2011-07-15 02:33:17 +0000642 PJ_ASSERT_RETURN(param, PJ_EINVAL);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000643 PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
644
Nanang Izzuddinbe321fd2011-07-15 02:33:17 +0000645 if (id <= PJMEDIA_VID_INVALID_DEV)
646 return PJMEDIA_EVID_INVDEV;
647
Benny Prijonoc45d9512010-12-10 11:04:30 +0000648 status = lookup_dev(id, &f, &index);
649 if (status != PJ_SUCCESS)
650 return status;
651
652 status = f->op->default_param(pool, f, index, param);
653 if (status != PJ_SUCCESS)
654 return status;
655
656 /* Normalize device IDs */
657 make_global_index(f->sys.drv_idx, &param->cap_id);
658 make_global_index(f->sys.drv_idx, &param->rend_id);
659
660 return PJ_SUCCESS;
661}
662
663/* API: Open video stream object using the specified parameters. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000664PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_create(
Sauw Ming5291a2d2011-07-15 07:52:44 +0000665 pjmedia_vid_dev_param *prm,
666 const pjmedia_vid_dev_cb *cb,
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000667 void *user_data,
668 pjmedia_vid_dev_stream **p_vid_strm)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000669{
670 pjmedia_vid_dev_factory *cap_f=NULL, *rend_f=NULL, *f=NULL;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000671 pj_status_t status;
672
673 PJ_ASSERT_RETURN(prm && prm->dir && p_vid_strm, PJ_EINVAL);
674 PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
675 PJ_ASSERT_RETURN(prm->dir==PJMEDIA_DIR_CAPTURE ||
676 prm->dir==PJMEDIA_DIR_RENDER ||
677 prm->dir==PJMEDIA_DIR_CAPTURE_RENDER,
678 PJ_EINVAL);
679
Benny Prijonoc45d9512010-12-10 11:04:30 +0000680 /* Normalize cap_id */
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000681 if (prm->dir & PJMEDIA_DIR_CAPTURE) {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000682 unsigned index;
683
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000684 if (prm->cap_id < 0)
685 prm->cap_id = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000686
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000687 status = lookup_dev(prm->cap_id, &cap_f, &index);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000688 if (status != PJ_SUCCESS)
689 return status;
690
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000691 prm->cap_id = index;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000692 f = cap_f;
693 }
694
695 /* Normalize rend_id */
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000696 if (prm->dir & PJMEDIA_DIR_RENDER) {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000697 unsigned index;
698
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000699 if (prm->rend_id < 0)
700 prm->rend_id = PJMEDIA_VID_DEFAULT_RENDER_DEV;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000701
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000702 status = lookup_dev(prm->rend_id, &rend_f, &index);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000703 if (status != PJ_SUCCESS)
704 return status;
705
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000706 prm->rend_id = index;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000707 f = rend_f;
708 }
709
710 PJ_ASSERT_RETURN(f != NULL, PJ_EBUG);
711
712 /* For now, cap_id and rend_id must belong to the same factory */
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000713 PJ_ASSERT_RETURN((prm->dir != PJMEDIA_DIR_CAPTURE_RENDER) ||
Benny Prijonoc45d9512010-12-10 11:04:30 +0000714 (cap_f == rend_f),
715 PJMEDIA_EVID_INVDEV);
716
717 /* Create the stream */
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000718 status = f->op->create_stream(f, prm, cb,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000719 user_data, p_vid_strm);
720 if (status != PJ_SUCCESS)
721 return status;
722
723 /* Assign factory id to the stream */
724 (*p_vid_strm)->sys.drv_idx = f->sys.drv_idx;
725 return PJ_SUCCESS;
726}
727
728/* API: Get the running parameters for the specified video stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000729PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_param(
730 pjmedia_vid_dev_stream *strm,
Sauw Ming5291a2d2011-07-15 07:52:44 +0000731 pjmedia_vid_dev_param *param)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000732{
733 pj_status_t status;
734
735 PJ_ASSERT_RETURN(strm && param, PJ_EINVAL);
736 PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
737
738 status = strm->op->get_param(strm, param);
739 if (status != PJ_SUCCESS)
740 return status;
741
742 /* Normalize device id's */
743 make_global_index(strm->sys.drv_idx, &param->cap_id);
744 make_global_index(strm->sys.drv_idx, &param->rend_id);
745
746 return PJ_SUCCESS;
747}
748
749/* API: Get the value of a specific capability of the video stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000750PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_cap(
751 pjmedia_vid_dev_stream *strm,
752 pjmedia_vid_dev_cap cap,
753 void *value)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000754{
755 return strm->op->get_cap(strm, cap, value);
756}
757
758/* API: Set the value of a specific capability of the video stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000759PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_set_cap(
760 pjmedia_vid_dev_stream *strm,
761 pjmedia_vid_dev_cap cap,
762 const void *value)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000763{
764 return strm->op->set_cap(strm, cap, value);
765}
766
Benny Prijono934af0f2011-07-12 03:05:35 +0000767PJ_DEF(pjmedia_event_publisher*)
768pjmedia_vid_dev_stream_get_event_publisher(pjmedia_vid_dev_stream *strm)
769{
770 return &strm->epub;
771}
772
Benny Prijonoc45d9512010-12-10 11:04:30 +0000773/* API: Start the stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000774PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_start(pjmedia_vid_dev_stream *strm)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000775{
776 return strm->op->start(strm);
777}
778
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000779PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_frame(
780 pjmedia_vid_dev_stream *strm,
781 pjmedia_frame *frame)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000782{
783 pj_assert(strm->op->get_frame);
784 return strm->op->get_frame(strm, frame);
785}
786
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000787PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_put_frame(
788 pjmedia_vid_dev_stream *strm,
789 const pjmedia_frame *frame)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000790{
791 pj_assert(strm->op->put_frame);
792 return strm->op->put_frame(strm, frame);
793}
794
795/* API: Stop the stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000796PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_stop(pjmedia_vid_dev_stream *strm)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000797{
798 return strm->op->stop(strm);
799}
800
801/* API: Destroy the stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000802PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_destroy(
803 pjmedia_vid_dev_stream *strm)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000804{
805 return strm->op->destroy(strm);
806}