blob: f626a555d012f47a99bf67c0ce7520f098d1af0a [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
Nanang Izzuddin63b3c132011-07-19 11:11:07 +000026
27#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
28
29
Benny Prijonoc45d9512010-12-10 11:04:30 +000030#define THIS_FILE "videodev.c"
31
32#define DEFINE_CAP(name, info) {name, info}
33
34/* Capability names */
35static struct cap_info
36{
37 const char *name;
38 const char *info;
39} cap_infos[] =
40{
41 DEFINE_CAP("format", "Video format"),
42 DEFINE_CAP("scale", "Input dimension"),
43 DEFINE_CAP("window", "Renderer window"),
Sauw Mingcbd82af2011-06-30 09:31:05 +000044 DEFINE_CAP("resize", "Renderer resize"),
45 DEFINE_CAP("position", "Renderer position"),
46 DEFINE_CAP("hide", "Renderer hide"),
Benny Prijonoc45d9512010-12-10 11:04:30 +000047};
48
49
50/*
51 * The device index seen by application and driver is different.
52 *
53 * At application level, device index is index to global list of device.
54 * At driver level, device index is index to device list on that particular
55 * factory only.
56 */
57#define MAKE_DEV_ID(f_id, index) (((f_id & 0xFFFF) << 16) | (index & 0xFFFF))
58#define GET_INDEX(dev_id) ((dev_id) & 0xFFFF)
59#define GET_FID(dev_id) ((dev_id) >> 16)
60#define DEFAULT_DEV_ID 0
61
62
63/* extern functions to create factories */
64#if PJMEDIA_VIDEO_DEV_HAS_NULL_VIDEO
65pjmedia_vid_dev_factory* pjmedia_null_video_factory(pj_pool_factory *pf);
66#endif
67
68#if PJMEDIA_VIDEO_DEV_HAS_DSHOW
69pjmedia_vid_dev_factory* pjmedia_dshow_factory(pj_pool_factory *pf);
70#endif
71
72#if PJMEDIA_VIDEO_DEV_HAS_CBAR_SRC
73pjmedia_vid_dev_factory* pjmedia_cbar_factory(pj_pool_factory *pf);
74#endif
75
76#if PJMEDIA_VIDEO_DEV_HAS_SDL
77pjmedia_vid_dev_factory* pjmedia_sdl_factory(pj_pool_factory *pf);
78#endif
79
80#if PJMEDIA_VIDEO_DEV_HAS_FFMPEG
81pjmedia_vid_dev_factory* pjmedia_ffmpeg_factory(pj_pool_factory *pf);
82#endif
83
84#if PJMEDIA_VIDEO_DEV_HAS_V4L2
85pjmedia_vid_dev_factory* pjmedia_v4l2_factory(pj_pool_factory *pf);
86#endif
87
Sauw Ming6e6c2152010-12-14 13:03:10 +000088#if PJMEDIA_VIDEO_DEV_HAS_QT
89pjmedia_vid_dev_factory* pjmedia_qt_factory(pj_pool_factory *pf);
90#endif
91
92#if PJMEDIA_VIDEO_DEV_HAS_IOS
93pjmedia_vid_dev_factory* pjmedia_ios_factory(pj_pool_factory *pf);
94#endif
95
Benny Prijonoc45d9512010-12-10 11:04:30 +000096#define MAX_DRIVERS 16
97#define MAX_DEVS 64
98
99
100/* driver structure */
101struct driver
102{
103 /* Creation function */
104 pjmedia_vid_dev_factory_create_func_ptr create;
105 /* Factory instance */
106 pjmedia_vid_dev_factory *f;
107 char name[32]; /* Driver name */
108 unsigned dev_cnt; /* Number of devices */
109 unsigned start_idx; /* Start index in global list */
110 int cap_dev_idx; /* Default capture device. */
111 int rend_dev_idx; /* Default render device */
112};
113
Sauw Minge90ece82011-06-09 04:05:44 +0000114/* The video device subsystem */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000115static struct vid_subsys
116{
117 unsigned init_count; /* How many times init() is called */
118 pj_pool_factory *pf; /* The pool factory. */
119
120 unsigned drv_cnt; /* Number of drivers. */
121 struct driver drv[MAX_DRIVERS]; /* Array of drivers. */
122
123 unsigned dev_cnt; /* Total number of devices. */
124 pj_uint32_t dev_list[MAX_DEVS];/* Array of device IDs. */
125
126} vid_subsys;
127
128/* API: get capability name/info */
129PJ_DEF(const char*) pjmedia_vid_dev_cap_name(pjmedia_vid_dev_cap cap,
130 const char **p_desc)
131{
132 const char *desc;
133 unsigned i;
134
135 if (p_desc==NULL) p_desc = &desc;
136
137 for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {
138 if ((1 << i)==cap)
139 break;
140 }
141
Benny Prijono333eaf12011-07-07 07:44:44 +0000142 if (i==PJ_ARRAY_SIZE(cap_infos)) {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000143 *p_desc = "??";
144 return "??";
145 }
146
147 *p_desc = cap_infos[i].info;
148 return cap_infos[i].name;
149}
150
Sauw Ming5291a2d2011-07-15 07:52:44 +0000151static pj_status_t get_cap_pointer(const pjmedia_vid_dev_param *param,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000152 pjmedia_vid_dev_cap cap,
153 void **ptr,
154 unsigned *size)
155{
156#define FIELD_INFO(name) *ptr = (void*)&param->name; \
157 *size = sizeof(param->name)
158
159 switch (cap) {
160 case PJMEDIA_VID_DEV_CAP_FORMAT:
161 FIELD_INFO(fmt);
162 break;
163 case PJMEDIA_VID_DEV_CAP_INPUT_SCALE:
164 FIELD_INFO(disp_size);
165 break;
166 case PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW:
167 FIELD_INFO(window);
168 break;
Sauw Mingcbd82af2011-06-30 09:31:05 +0000169 case PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE:
170 FIELD_INFO(disp_size);
171 break;
172 case PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION:
173 FIELD_INFO(window_pos);
174 break;
175 case PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE:
176 FIELD_INFO(window_hide);
177 break;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000178 default:
179 return PJMEDIA_EVID_INVCAP;
180 }
181
182#undef FIELD_INFO
183
184 return PJ_SUCCESS;
185}
186
187/* API: set cap value to param */
Sauw Ming5291a2d2011-07-15 07:52:44 +0000188PJ_DEF(pj_status_t)
189pjmedia_vid_dev_param_set_cap( pjmedia_vid_dev_param *param,
190 pjmedia_vid_dev_cap cap,
191 const void *pval)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000192{
193 void *cap_ptr;
194 unsigned cap_size;
195 pj_status_t status;
196
197 status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
198 if (status != PJ_SUCCESS)
199 return status;
200
201 pj_memcpy(cap_ptr, pval, cap_size);
202 param->flags |= cap;
203
204 return PJ_SUCCESS;
205}
206
207/* API: get cap value from param */
Sauw Ming5291a2d2011-07-15 07:52:44 +0000208PJ_DEF(pj_status_t)
209pjmedia_vid_dev_param_get_cap( const pjmedia_vid_dev_param *param,
210 pjmedia_vid_dev_cap cap,
211 void *pval)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000212{
213 void *cap_ptr;
214 unsigned cap_size;
215 pj_status_t status;
216
217 status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
218 if (status != PJ_SUCCESS)
219 return status;
220
221 if ((param->flags & cap) == 0) {
222 pj_bzero(cap_ptr, cap_size);
223 return PJMEDIA_EVID_INVCAP;
224 }
225
226 pj_memcpy(pval, cap_ptr, cap_size);
227 return PJ_SUCCESS;
228}
229
230/* Internal: init driver */
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000231static pj_status_t init_driver(unsigned drv_idx, pj_bool_t refresh)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000232{
233 struct driver *drv = &vid_subsys.drv[drv_idx];
234 pjmedia_vid_dev_factory *f;
235 unsigned i, dev_cnt;
236 pj_status_t status;
237
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000238 if (!refresh) {
239 /* Create the factory */
240 f = (*drv->create)(vid_subsys.pf);
241 if (!f)
242 return PJ_EUNKNOWN;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000243
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000244 /* Call factory->init() */
245 status = f->op->init(f);
246 if (status != PJ_SUCCESS) {
247 f->op->destroy(f);
248 return status;
249 }
250 } else {
251 f = drv->f;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000252 }
253
254 /* Get number of devices */
255 dev_cnt = f->op->get_dev_count(f);
256 if (dev_cnt + vid_subsys.dev_cnt > MAX_DEVS) {
257 PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because"
258 " there are too many devices",
259 vid_subsys.dev_cnt + dev_cnt - MAX_DEVS));
260 dev_cnt = MAX_DEVS - vid_subsys.dev_cnt;
261 }
262
263 /* enabling this will cause pjsua-lib initialization to fail when there
264 * is no video device installed in the system, even when pjsua has been
265 * run with --null-video
266 *
267 if (dev_cnt == 0) {
268 f->op->destroy(f);
269 return PJMEDIA_EVID_NODEV;
270 }
271 */
272
273 /* Fill in default devices */
274 drv->rend_dev_idx = drv->cap_dev_idx = -1;
275 for (i=0; i<dev_cnt; ++i) {
276 pjmedia_vid_dev_info info;
277
278 status = f->op->get_dev_info(f, i, &info);
279 if (status != PJ_SUCCESS) {
280 f->op->destroy(f);
281 return status;
282 }
283
284 if (drv->name[0]=='\0') {
285 /* Set driver name */
286 pj_ansi_strncpy(drv->name, info.driver, sizeof(drv->name));
287 drv->name[sizeof(drv->name)-1] = '\0';
288 }
289
290 if (drv->rend_dev_idx < 0 && (info.dir & PJMEDIA_DIR_RENDER)) {
291 /* Set default render device */
292 drv->rend_dev_idx = i;
293 }
294 if (drv->cap_dev_idx < 0 && (info.dir & PJMEDIA_DIR_CAPTURE)) {
295 /* Set default capture device */
296 drv->cap_dev_idx = i;
297 }
298
299 if (drv->rend_dev_idx >= 0 && drv->cap_dev_idx >= 0) {
300 /* Done. */
301 break;
302 }
303 }
304
305 /* Register the factory */
306 drv->f = f;
307 drv->f->sys.drv_idx = drv_idx;
308 drv->start_idx = vid_subsys.dev_cnt;
309 drv->dev_cnt = dev_cnt;
310
311 /* Register devices to global list */
312 for (i=0; i<dev_cnt; ++i) {
313 vid_subsys.dev_list[vid_subsys.dev_cnt++] = MAKE_DEV_ID(drv_idx, i);
314 }
315
316 return PJ_SUCCESS;
317}
318
319/* Internal: deinit driver */
320static void deinit_driver(unsigned drv_idx)
321{
322 struct driver *drv = &vid_subsys.drv[drv_idx];
323
324 if (drv->f) {
325 drv->f->op->destroy(drv->f);
326 drv->f = NULL;
327 }
328
329 drv->dev_cnt = 0;
330 drv->rend_dev_idx = drv->cap_dev_idx = -1;
331}
332
Sauw Minge90ece82011-06-09 04:05:44 +0000333/* API: Initialize the video device subsystem. */
334PJ_DEF(pj_status_t) pjmedia_vid_dev_subsys_init(pj_pool_factory *pf)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000335{
336 unsigned i;
337 pj_status_t status = PJ_SUCCESS;
338
339 /* Allow init() to be called multiple times as long as there is matching
340 * number of shutdown().
341 */
342 if (vid_subsys.init_count++ != 0) {
343 return PJ_SUCCESS;
344 }
345
346 /* Register error subsystem */
347 pj_register_strerror(PJMEDIA_VIDEODEV_ERRNO_START,
348 PJ_ERRNO_SPACE_SIZE,
349 &pjmedia_videodev_strerror);
350
351 /* Init */
352 vid_subsys.pf = pf;
353 vid_subsys.drv_cnt = 0;
354 vid_subsys.dev_cnt = 0;
355
356 /* Register creation functions */
357#if PJMEDIA_VIDEO_DEV_HAS_V4L2
358 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_v4l2_factory;
359#endif
Sauw Ming6e6c2152010-12-14 13:03:10 +0000360#if PJMEDIA_VIDEO_DEV_HAS_QT
361 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_qt_factory;
362#endif
363#if PJMEDIA_VIDEO_DEV_HAS_IOS
364 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_ios_factory;
365#endif
Benny Prijonoc45d9512010-12-10 11:04:30 +0000366#if PJMEDIA_VIDEO_DEV_HAS_DSHOW
367 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_dshow_factory;
368#endif
369#if PJMEDIA_VIDEO_DEV_HAS_FFMPEG
370 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_ffmpeg_factory;
371#endif
372#if PJMEDIA_VIDEO_DEV_HAS_CBAR_SRC
373 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_cbar_factory;
374#endif
375#if PJMEDIA_VIDEO_DEV_HAS_SDL
376 vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_sdl_factory;
377#endif
378
379 /* Initialize each factory and build the device ID list */
380 for (i=0; i<vid_subsys.drv_cnt; ++i) {
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000381 status = init_driver(i, PJ_FALSE);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000382 if (status != PJ_SUCCESS) {
383 deinit_driver(i);
384 continue;
385 }
386 }
387
388 return vid_subsys.dev_cnt ? PJ_SUCCESS : status;
389}
390
Sauw Minge90ece82011-06-09 04:05:44 +0000391/* API: register a video device factory to the video device subsystem. */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000392PJ_DEF(pj_status_t)
393pjmedia_vid_register_factory(pjmedia_vid_dev_factory_create_func_ptr adf)
394{
395 pj_status_t status;
396
397 if (vid_subsys.init_count == 0)
398 return PJMEDIA_EVID_INIT;
399
400 vid_subsys.drv[vid_subsys.drv_cnt].create = adf;
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000401 status = init_driver(vid_subsys.drv_cnt, PJ_FALSE);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000402 if (status == PJ_SUCCESS) {
403 vid_subsys.drv_cnt++;
404 } else {
405 deinit_driver(vid_subsys.drv_cnt);
406 }
407
408 return status;
409}
410
Sauw Minge90ece82011-06-09 04:05:44 +0000411/* API: unregister a video device factory from the video device subsystem. */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000412PJ_DEF(pj_status_t)
413pjmedia_vid_unregister_factory(pjmedia_vid_dev_factory_create_func_ptr adf)
414{
415 unsigned i, j;
416
417 if (vid_subsys.init_count == 0)
418 return PJMEDIA_EVID_INIT;
419
420 for (i=0; i<vid_subsys.drv_cnt; ++i) {
421 struct driver *drv = &vid_subsys.drv[i];
422
423 if (drv->create == adf) {
424 for (j = drv->start_idx; j < drv->start_idx + drv->dev_cnt; j++)
425 {
426 vid_subsys.dev_list[j] = (pj_uint32_t)PJMEDIA_VID_INVALID_DEV;
427 }
428
429 deinit_driver(i);
430 pj_bzero(drv, sizeof(*drv));
431 return PJ_SUCCESS;
432 }
433 }
434
435 return PJMEDIA_EVID_ERR;
436}
437
Sauw Minge90ece82011-06-09 04:05:44 +0000438/* API: get the pool factory registered to the video device subsystem. */
439PJ_DEF(pj_pool_factory*) pjmedia_vid_dev_subsys_get_pool_factory(void)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000440{
441 return vid_subsys.pf;
442}
443
Sauw Minge90ece82011-06-09 04:05:44 +0000444/* API: Shutdown the video device subsystem. */
445PJ_DEF(pj_status_t) pjmedia_vid_dev_subsys_shutdown(void)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000446{
447 unsigned i;
448
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000449 /* Allow shutdown() to be called multiple times as long as there is
450 * matching number of init().
Benny Prijonoc45d9512010-12-10 11:04:30 +0000451 */
452 if (vid_subsys.init_count == 0) {
453 return PJ_SUCCESS;
454 }
455 --vid_subsys.init_count;
456
Sauw Minge90ece82011-06-09 04:05:44 +0000457 if (vid_subsys.init_count == 0) {
458 for (i=0; i<vid_subsys.drv_cnt; ++i) {
459 deinit_driver(i);
460 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000461
Sauw Minge90ece82011-06-09 04:05:44 +0000462 vid_subsys.pf = NULL;
463 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000464 return PJ_SUCCESS;
465}
466
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000467/* API: Refresh the list of video devices installed in the system. */
468PJ_DEF(pj_status_t) pjmedia_vid_dev_refresh(void)
469{
470 unsigned i;
471
472 vid_subsys.dev_cnt = 0;
473 for (i=0; i<vid_subsys.drv_cnt; ++i) {
474 struct driver *drv = &vid_subsys.drv[i];
475
476 if (drv->f && drv->f->op->refresh) {
477 pj_status_t status = drv->f->op->refresh(drv->f);
478 if (status != PJ_SUCCESS) {
479 PJ_PERROR(4, (THIS_FILE, status, "Unable to refresh device "
480 "list for %s", drv->name));
481 }
482 }
483 init_driver(i, PJ_TRUE);
484 }
485 return PJ_SUCCESS;
486}
487
Benny Prijonoc45d9512010-12-10 11:04:30 +0000488/* API: Get the number of video devices installed in the system. */
489PJ_DEF(unsigned) pjmedia_vid_dev_count(void)
490{
491 return vid_subsys.dev_cnt;
492}
493
494/* Internal: convert local index to global device index */
495static pj_status_t make_global_index(unsigned drv_idx,
496 pjmedia_vid_dev_index *id)
497{
498 if (*id < 0) {
499 return PJ_SUCCESS;
500 }
501
502 /* Check that factory still exists */
503 PJ_ASSERT_RETURN(vid_subsys.drv[drv_idx].f, PJ_EBUG);
504
505 /* Check that device index is valid */
506 PJ_ASSERT_RETURN(*id>=0 && *id<(int)vid_subsys.drv[drv_idx].dev_cnt,
507 PJ_EBUG);
508
509 *id += vid_subsys.drv[drv_idx].start_idx;
510 return PJ_SUCCESS;
511}
512
513/* Internal: lookup device id */
514static pj_status_t lookup_dev(pjmedia_vid_dev_index id,
515 pjmedia_vid_dev_factory **p_f,
516 unsigned *p_local_index)
517{
518 int f_id, index;
519
520 if (id < 0) {
521 unsigned i;
522
Nanang Izzuddinbe321fd2011-07-15 02:33:17 +0000523 if (id <= PJMEDIA_VID_INVALID_DEV)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000524 return PJMEDIA_EVID_INVDEV;
525
526 for (i=0; i<vid_subsys.drv_cnt; ++i) {
527 struct driver *drv = &vid_subsys.drv[i];
528 if (id==PJMEDIA_VID_DEFAULT_CAPTURE_DEV &&
529 drv->cap_dev_idx >= 0)
530 {
531 id = drv->cap_dev_idx;
532 make_global_index(i, &id);
533 break;
534 } else if (id==PJMEDIA_VID_DEFAULT_RENDER_DEV &&
535 drv->rend_dev_idx >= 0)
536 {
537 id = drv->rend_dev_idx;
538 make_global_index(i, &id);
539 break;
540 }
541 }
542
543 if (id < 0) {
544 return PJMEDIA_EVID_NODEFDEV;
545 }
546 }
547
548 f_id = GET_FID(vid_subsys.dev_list[id]);
549 index = GET_INDEX(vid_subsys.dev_list[id]);
550
551 if (f_id < 0 || f_id >= (int)vid_subsys.drv_cnt)
552 return PJMEDIA_EVID_INVDEV;
553
554 if (index < 0 || index >= (int)vid_subsys.drv[f_id].dev_cnt)
555 return PJMEDIA_EVID_INVDEV;
556
557 *p_f = vid_subsys.drv[f_id].f;
558 *p_local_index = (unsigned)index;
559
560 return PJ_SUCCESS;
561
562}
563
564/* API: Get device information. */
565PJ_DEF(pj_status_t) pjmedia_vid_dev_get_info(pjmedia_vid_dev_index id,
566 pjmedia_vid_dev_info *info)
567{
568 pjmedia_vid_dev_factory *f;
569 unsigned index;
570 pj_status_t status;
571
Nanang Izzuddinbe321fd2011-07-15 02:33:17 +0000572 PJ_ASSERT_RETURN(info, PJ_EINVAL);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000573 PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
574
Nanang Izzuddinbe321fd2011-07-15 02:33:17 +0000575 if (id <= PJMEDIA_VID_INVALID_DEV)
576 return PJMEDIA_EVID_INVDEV;
577
Benny Prijonoc45d9512010-12-10 11:04:30 +0000578 status = lookup_dev(id, &f, &index);
579 if (status != PJ_SUCCESS)
580 return status;
581
Nanang Izzuddinf4ee4152011-07-12 03:20:36 +0000582 status = f->op->get_dev_info(f, index, info);
583
584 /* Make sure device ID is the real ID (not PJMEDIA_VID_DEFAULT_*_DEV) */
585 info->id = index;
Nanang Izzuddin32b924f2011-07-13 13:23:29 +0000586 make_global_index(f->sys.drv_idx, &info->id);
Nanang Izzuddinf4ee4152011-07-12 03:20:36 +0000587
588 return status;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000589}
590
591/* API: find device */
592PJ_DEF(pj_status_t) pjmedia_vid_dev_lookup( const char *drv_name,
593 const char *dev_name,
594 pjmedia_vid_dev_index *id)
595{
596 pjmedia_vid_dev_factory *f = NULL;
597 unsigned drv_idx, dev_idx;
598
599 PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);
600 PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
601
602 for (drv_idx=0; drv_idx<vid_subsys.drv_cnt; ++drv_idx) {
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000603 if (!pj_ansi_stricmp(drv_name, vid_subsys.drv[drv_idx].name))
604 {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000605 f = vid_subsys.drv[drv_idx].f;
606 break;
607 }
608 }
609
610 if (!f)
611 return PJ_ENOTFOUND;
612
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000613 for (dev_idx=0; dev_idx<vid_subsys.drv[drv_idx].dev_cnt; ++dev_idx)
614 {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000615 pjmedia_vid_dev_info info;
616 pj_status_t status;
617
618 status = f->op->get_dev_info(f, dev_idx, &info);
619 if (status != PJ_SUCCESS)
620 return status;
621
622 if (!pj_ansi_stricmp(dev_name, info.name))
623 break;
624 }
625
626 if (dev_idx==vid_subsys.drv[drv_idx].dev_cnt)
627 return PJ_ENOTFOUND;
628
629 *id = dev_idx;
630 make_global_index(drv_idx, id);
631
632 return PJ_SUCCESS;
633}
634
635/* API: Initialize the video device parameters with default values for the
636 * specified device.
637 */
638PJ_DEF(pj_status_t) pjmedia_vid_dev_default_param(pj_pool_t *pool,
639 pjmedia_vid_dev_index id,
Sauw Ming5291a2d2011-07-15 07:52:44 +0000640 pjmedia_vid_dev_param *param)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000641{
642 pjmedia_vid_dev_factory *f;
643 unsigned index;
644 pj_status_t status;
645
Nanang Izzuddinbe321fd2011-07-15 02:33:17 +0000646 PJ_ASSERT_RETURN(param, PJ_EINVAL);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000647 PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
648
Nanang Izzuddinbe321fd2011-07-15 02:33:17 +0000649 if (id <= PJMEDIA_VID_INVALID_DEV)
650 return PJMEDIA_EVID_INVDEV;
651
Benny Prijonoc45d9512010-12-10 11:04:30 +0000652 status = lookup_dev(id, &f, &index);
653 if (status != PJ_SUCCESS)
654 return status;
655
656 status = f->op->default_param(pool, f, index, param);
657 if (status != PJ_SUCCESS)
658 return status;
659
660 /* Normalize device IDs */
661 make_global_index(f->sys.drv_idx, &param->cap_id);
662 make_global_index(f->sys.drv_idx, &param->rend_id);
663
664 return PJ_SUCCESS;
665}
666
667/* API: Open video stream object using the specified parameters. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000668PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_create(
Sauw Ming5291a2d2011-07-15 07:52:44 +0000669 pjmedia_vid_dev_param *prm,
670 const pjmedia_vid_dev_cb *cb,
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000671 void *user_data,
672 pjmedia_vid_dev_stream **p_vid_strm)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000673{
674 pjmedia_vid_dev_factory *cap_f=NULL, *rend_f=NULL, *f=NULL;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000675 pj_status_t status;
676
677 PJ_ASSERT_RETURN(prm && prm->dir && p_vid_strm, PJ_EINVAL);
678 PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
679 PJ_ASSERT_RETURN(prm->dir==PJMEDIA_DIR_CAPTURE ||
680 prm->dir==PJMEDIA_DIR_RENDER ||
681 prm->dir==PJMEDIA_DIR_CAPTURE_RENDER,
682 PJ_EINVAL);
683
Benny Prijonoc45d9512010-12-10 11:04:30 +0000684 /* Normalize cap_id */
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000685 if (prm->dir & PJMEDIA_DIR_CAPTURE) {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000686 unsigned index;
687
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000688 if (prm->cap_id < 0)
689 prm->cap_id = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000690
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000691 status = lookup_dev(prm->cap_id, &cap_f, &index);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000692 if (status != PJ_SUCCESS)
693 return status;
694
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000695 prm->cap_id = index;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000696 f = cap_f;
697 }
698
699 /* Normalize rend_id */
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000700 if (prm->dir & PJMEDIA_DIR_RENDER) {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000701 unsigned index;
702
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000703 if (prm->rend_id < 0)
704 prm->rend_id = PJMEDIA_VID_DEFAULT_RENDER_DEV;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000705
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000706 status = lookup_dev(prm->rend_id, &rend_f, &index);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000707 if (status != PJ_SUCCESS)
708 return status;
709
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000710 prm->rend_id = index;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000711 f = rend_f;
712 }
713
714 PJ_ASSERT_RETURN(f != NULL, PJ_EBUG);
715
716 /* For now, cap_id and rend_id must belong to the same factory */
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000717 PJ_ASSERT_RETURN((prm->dir != PJMEDIA_DIR_CAPTURE_RENDER) ||
Benny Prijonoc45d9512010-12-10 11:04:30 +0000718 (cap_f == rend_f),
719 PJMEDIA_EVID_INVDEV);
720
721 /* Create the stream */
Benny Prijonoe9f70d82011-03-25 08:38:26 +0000722 status = f->op->create_stream(f, prm, cb,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000723 user_data, p_vid_strm);
724 if (status != PJ_SUCCESS)
725 return status;
726
727 /* Assign factory id to the stream */
728 (*p_vid_strm)->sys.drv_idx = f->sys.drv_idx;
729 return PJ_SUCCESS;
730}
731
732/* API: Get the running parameters for the specified video stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000733PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_param(
734 pjmedia_vid_dev_stream *strm,
Sauw Ming5291a2d2011-07-15 07:52:44 +0000735 pjmedia_vid_dev_param *param)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000736{
737 pj_status_t status;
738
739 PJ_ASSERT_RETURN(strm && param, PJ_EINVAL);
740 PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
741
742 status = strm->op->get_param(strm, param);
743 if (status != PJ_SUCCESS)
744 return status;
745
746 /* Normalize device id's */
747 make_global_index(strm->sys.drv_idx, &param->cap_id);
748 make_global_index(strm->sys.drv_idx, &param->rend_id);
749
750 return PJ_SUCCESS;
751}
752
753/* API: Get the value of a specific capability of the video stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000754PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_cap(
755 pjmedia_vid_dev_stream *strm,
756 pjmedia_vid_dev_cap cap,
757 void *value)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000758{
759 return strm->op->get_cap(strm, cap, value);
760}
761
762/* API: Set the value of a specific capability of the video stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000763PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_set_cap(
764 pjmedia_vid_dev_stream *strm,
765 pjmedia_vid_dev_cap cap,
766 const void *value)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000767{
768 return strm->op->set_cap(strm, cap, value);
769}
770
Benny Prijono934af0f2011-07-12 03:05:35 +0000771PJ_DEF(pjmedia_event_publisher*)
772pjmedia_vid_dev_stream_get_event_publisher(pjmedia_vid_dev_stream *strm)
773{
774 return &strm->epub;
775}
776
Benny Prijonoc45d9512010-12-10 11:04:30 +0000777/* API: Start the stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000778PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_start(pjmedia_vid_dev_stream *strm)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000779{
780 return strm->op->start(strm);
781}
782
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000783PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_frame(
784 pjmedia_vid_dev_stream *strm,
785 pjmedia_frame *frame)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000786{
787 pj_assert(strm->op->get_frame);
788 return strm->op->get_frame(strm, frame);
789}
790
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000791PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_put_frame(
792 pjmedia_vid_dev_stream *strm,
793 const pjmedia_frame *frame)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000794{
795 pj_assert(strm->op->put_frame);
796 return strm->op->put_frame(strm, frame);
797}
798
799/* API: Stop the stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000800PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_stop(pjmedia_vid_dev_stream *strm)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000801{
802 return strm->op->stop(strm);
803}
804
805/* API: Destroy the stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000806PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_destroy(
807 pjmedia_vid_dev_stream *strm)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000808{
809 return strm->op->destroy(strm);
810}
Nanang Izzuddin63b3c132011-07-19 11:11:07 +0000811
812
813#endif /* PJMEDIA_HAS_VIDEO */