~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjmedia/src/pjmedia-videodev/videodev.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: videodev.c 4016 2012-04-04 05:05:50Z bennylp $ */
 
2
/* 
 
3
 * Copyright (C) 2008-2011 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
 
 
27
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
 
28
 
 
29
 
 
30
#define THIS_FILE   "videodev.c"
 
31
 
 
32
#define DEFINE_CAP(name, info)  {name, info}
 
33
 
 
34
/* Capability names */
 
35
static 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",        "Window handle"),
 
44
    DEFINE_CAP("resize",        "Renderer resize"),
 
45
    DEFINE_CAP("position",      "Renderer position"),
 
46
    DEFINE_CAP("hide",          "Renderer hide"),
 
47
    DEFINE_CAP("preview",       "Input preview"),
 
48
    DEFINE_CAP("orientation",   "Video orientation"),
 
49
    DEFINE_CAP("switch",        "Switch device"),
 
50
    DEFINE_CAP("wndflags",      "Window flags")
 
51
};
 
52
 
 
53
 
 
54
/*
 
55
 * The device index seen by application and driver is different. 
 
56
 *
 
57
 * At application level, device index is index to global list of device.
 
58
 * At driver level, device index is index to device list on that particular
 
59
 * factory only.
 
60
 */
 
61
#define MAKE_DEV_ID(f_id, index)   (((f_id & 0xFFFF) << 16) | (index & 0xFFFF))
 
62
#define GET_INDEX(dev_id)          ((dev_id) & 0xFFFF)
 
63
#define GET_FID(dev_id)            ((dev_id) >> 16)
 
64
#define DEFAULT_DEV_ID              0
 
65
 
 
66
 
 
67
/* extern functions to create factories */
 
68
#if PJMEDIA_VIDEO_DEV_HAS_NULL_VIDEO
 
69
pjmedia_vid_dev_factory* pjmedia_null_video_factory(pj_pool_factory *pf);
 
70
#endif
 
71
 
 
72
#if PJMEDIA_VIDEO_DEV_HAS_DSHOW
 
73
pjmedia_vid_dev_factory* pjmedia_dshow_factory(pj_pool_factory *pf);
 
74
#endif
 
75
 
 
76
#if PJMEDIA_VIDEO_DEV_HAS_CBAR_SRC
 
77
pjmedia_vid_dev_factory* pjmedia_cbar_factory(pj_pool_factory *pf);
 
78
#endif
 
79
 
 
80
#if PJMEDIA_VIDEO_DEV_HAS_SDL
 
81
pjmedia_vid_dev_factory* pjmedia_sdl_factory(pj_pool_factory *pf);
 
82
#endif
 
83
 
 
84
#if PJMEDIA_VIDEO_DEV_HAS_FFMPEG
 
85
pjmedia_vid_dev_factory* pjmedia_ffmpeg_factory(pj_pool_factory *pf);
 
86
#endif
 
87
 
 
88
#if PJMEDIA_VIDEO_DEV_HAS_V4L2
 
89
pjmedia_vid_dev_factory* pjmedia_v4l2_factory(pj_pool_factory *pf);
 
90
#endif
 
91
 
 
92
#if PJMEDIA_VIDEO_DEV_HAS_QT
 
93
pjmedia_vid_dev_factory* pjmedia_qt_factory(pj_pool_factory *pf);
 
94
#endif
 
95
 
 
96
#if PJMEDIA_VIDEO_DEV_HAS_IOS
 
97
pjmedia_vid_dev_factory* pjmedia_ios_factory(pj_pool_factory *pf);
 
98
#endif
 
99
 
 
100
#define MAX_DRIVERS     16
 
101
#define MAX_DEVS        64
 
102
 
 
103
 
 
104
/* driver structure */
 
105
struct driver
 
106
{
 
107
    /* Creation function */
 
108
    pjmedia_vid_dev_factory_create_func_ptr create;
 
109
    /* Factory instance */
 
110
    pjmedia_vid_dev_factory *f;
 
111
    char                     name[32];      /* Driver name                  */
 
112
    unsigned                 dev_cnt;       /* Number of devices            */
 
113
    unsigned                 start_idx;     /* Start index in global list   */
 
114
    int                      cap_dev_idx;   /* Default capture device.      */
 
115
    int                      rend_dev_idx;  /* Default render device        */
 
116
};
 
117
 
 
118
/* The video device subsystem */
 
119
static struct vid_subsys
 
120
{
 
121
    unsigned         init_count;        /* How many times init() is called  */
 
122
    pj_pool_factory *pf;                /* The pool factory.                */
 
123
 
 
124
    unsigned         drv_cnt;           /* Number of drivers.               */
 
125
    struct driver    drv[MAX_DRIVERS];  /* Array of drivers.                */
 
126
 
 
127
    unsigned         dev_cnt;           /* Total number of devices.         */
 
128
    pj_uint32_t      dev_list[MAX_DEVS];/* Array of device IDs.             */
 
129
 
 
130
} vid_subsys;
 
131
 
 
132
/* API: get capability name/info */
 
133
PJ_DEF(const char*) pjmedia_vid_dev_cap_name(pjmedia_vid_dev_cap cap,
 
134
                                             const char **p_desc)
 
135
{
 
136
    const char *desc;
 
137
    unsigned i;
 
138
 
 
139
    if (p_desc==NULL) p_desc = &desc;
 
140
 
 
141
    for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {
 
142
        if ((1 << i)==cap)
 
143
            break;
 
144
    }
 
145
 
 
146
    if (i==PJ_ARRAY_SIZE(cap_infos)) {
 
147
        *p_desc = "??";
 
148
        return "??";
 
149
    }
 
150
 
 
151
    *p_desc = cap_infos[i].info;
 
152
    return cap_infos[i].name;
 
153
}
 
154
 
 
155
static pj_status_t get_cap_pointer(const pjmedia_vid_dev_param *param,
 
156
                                   pjmedia_vid_dev_cap cap,
 
157
                                   void **ptr,
 
158
                                   unsigned *size)
 
159
{
 
160
#define FIELD_INFO(name)    *ptr = (void*)&param->name; \
 
161
                            *size = sizeof(param->name)
 
162
 
 
163
    switch (cap) {
 
164
    case PJMEDIA_VID_DEV_CAP_FORMAT:
 
165
        FIELD_INFO(fmt);
 
166
        break;
 
167
    case PJMEDIA_VID_DEV_CAP_INPUT_SCALE:
 
168
        FIELD_INFO(disp_size);
 
169
        break;
 
170
    case PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW:
 
171
        FIELD_INFO(window);
 
172
        break;
 
173
    case PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE:
 
174
        FIELD_INFO(disp_size);
 
175
        break;
 
176
    case PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION:
 
177
        FIELD_INFO(window_pos);
 
178
        break;
 
179
    case PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE:
 
180
        FIELD_INFO(window_hide);
 
181
        break;
 
182
    case PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW:
 
183
        FIELD_INFO(native_preview);
 
184
        break;
 
185
    case PJMEDIA_VID_DEV_CAP_ORIENTATION:
 
186
        FIELD_INFO(orient);
 
187
        break;
 
188
    /* The PJMEDIA_VID_DEV_CAP_SWITCH does not have an entry in the
 
189
     * param (it doesn't make sense to open a stream and tell it
 
190
     * to switch immediately).
 
191
     */
 
192
    case PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS:
 
193
        FIELD_INFO(window_flags);
 
194
        break;
 
195
    default:
 
196
        return PJMEDIA_EVID_INVCAP;
 
197
    }
 
198
 
 
199
#undef FIELD_INFO
 
200
 
 
201
    return PJ_SUCCESS;
 
202
}
 
203
 
 
204
/* API: set cap value to param */
 
205
PJ_DEF(pj_status_t)
 
206
pjmedia_vid_dev_param_set_cap( pjmedia_vid_dev_param *param,
 
207
                               pjmedia_vid_dev_cap cap,
 
208
                               const void *pval)
 
209
{
 
210
    void *cap_ptr;
 
211
    unsigned cap_size;
 
212
    pj_status_t status;
 
213
 
 
214
    status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
 
215
    if (status != PJ_SUCCESS)
 
216
        return status;
 
217
 
 
218
    pj_memcpy(cap_ptr, pval, cap_size);
 
219
    param->flags |= cap;
 
220
 
 
221
    return PJ_SUCCESS;
 
222
}
 
223
 
 
224
/* API: get cap value from param */
 
225
PJ_DEF(pj_status_t)
 
226
pjmedia_vid_dev_param_get_cap( const pjmedia_vid_dev_param *param,
 
227
                               pjmedia_vid_dev_cap cap,
 
228
                               void *pval)
 
229
{
 
230
    void *cap_ptr;
 
231
    unsigned cap_size;
 
232
    pj_status_t status;
 
233
 
 
234
    status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
 
235
    if (status != PJ_SUCCESS)
 
236
        return status;
 
237
 
 
238
    if ((param->flags & cap) == 0) {
 
239
        pj_bzero(cap_ptr, cap_size);
 
240
        return PJMEDIA_EVID_INVCAP;
 
241
    }
 
242
 
 
243
    pj_memcpy(pval, cap_ptr, cap_size);
 
244
    return PJ_SUCCESS;
 
245
}
 
246
 
 
247
/* Internal: init driver */
 
248
static pj_status_t init_driver(unsigned drv_idx, pj_bool_t refresh)
 
249
{
 
250
    struct driver *drv = &vid_subsys.drv[drv_idx];
 
251
    pjmedia_vid_dev_factory *f;
 
252
    unsigned i, dev_cnt;
 
253
    pj_status_t status;
 
254
 
 
255
    if (!refresh) {
 
256
        /* Create the factory */
 
257
        f = (*drv->create)(vid_subsys.pf);
 
258
        if (!f)
 
259
            return PJ_EUNKNOWN;
 
260
 
 
261
        /* Call factory->init() */
 
262
        status = f->op->init(f);
 
263
        if (status != PJ_SUCCESS) {
 
264
            f->op->destroy(f);
 
265
            return status;
 
266
        }
 
267
    } else {
 
268
        f = drv->f;
 
269
    }
 
270
 
 
271
    /* Get number of devices */
 
272
    dev_cnt = f->op->get_dev_count(f);
 
273
    if (dev_cnt + vid_subsys.dev_cnt > MAX_DEVS) {
 
274
        PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because"
 
275
                              " there are too many devices",
 
276
                              vid_subsys.dev_cnt + dev_cnt - MAX_DEVS));
 
277
        dev_cnt = MAX_DEVS - vid_subsys.dev_cnt;
 
278
    }
 
279
 
 
280
    /* enabling this will cause pjsua-lib initialization to fail when there
 
281
     * is no video device installed in the system, even when pjsua has been
 
282
     * run with --null-video
 
283
     *
 
284
    if (dev_cnt == 0) {
 
285
        f->op->destroy(f);
 
286
        return PJMEDIA_EVID_NODEV;
 
287
    }
 
288
    */
 
289
 
 
290
    /* Fill in default devices */
 
291
    drv->rend_dev_idx = drv->cap_dev_idx = -1;
 
292
    for (i=0; i<dev_cnt; ++i) {
 
293
        pjmedia_vid_dev_info info;
 
294
 
 
295
        status = f->op->get_dev_info(f, i, &info);
 
296
        if (status != PJ_SUCCESS) {
 
297
            f->op->destroy(f);
 
298
            return status;
 
299
        }
 
300
 
 
301
        if (drv->name[0]=='\0') {
 
302
            /* Set driver name */
 
303
            pj_ansi_strncpy(drv->name, info.driver, sizeof(drv->name));
 
304
            drv->name[sizeof(drv->name)-1] = '\0';
 
305
        }
 
306
 
 
307
        if (drv->rend_dev_idx < 0 && (info.dir & PJMEDIA_DIR_RENDER)) {
 
308
            /* Set default render device */
 
309
            drv->rend_dev_idx = i;
 
310
        }
 
311
        if (drv->cap_dev_idx < 0 && (info.dir & PJMEDIA_DIR_CAPTURE)) {
 
312
            /* Set default capture device */
 
313
            drv->cap_dev_idx = i;
 
314
        }
 
315
 
 
316
        if (drv->rend_dev_idx >= 0 && drv->cap_dev_idx >= 0) {
 
317
            /* Done. */
 
318
            break;
 
319
        }
 
320
    }
 
321
 
 
322
    /* Register the factory */
 
323
    drv->f = f;
 
324
    drv->f->sys.drv_idx = drv_idx;
 
325
    drv->start_idx = vid_subsys.dev_cnt;
 
326
    drv->dev_cnt = dev_cnt;
 
327
 
 
328
    /* Register devices to global list */
 
329
    for (i=0; i<dev_cnt; ++i) {
 
330
        vid_subsys.dev_list[vid_subsys.dev_cnt++] = MAKE_DEV_ID(drv_idx, i);
 
331
    }
 
332
 
 
333
    return PJ_SUCCESS;
 
334
}
 
335
 
 
336
/* Internal: deinit driver */
 
337
static void deinit_driver(unsigned drv_idx)
 
338
{
 
339
    struct driver *drv = &vid_subsys.drv[drv_idx];
 
340
 
 
341
    if (drv->f) {
 
342
        drv->f->op->destroy(drv->f);
 
343
        drv->f = NULL;
 
344
    }
 
345
 
 
346
    drv->dev_cnt = 0;
 
347
    drv->rend_dev_idx = drv->cap_dev_idx = -1;
 
348
}
 
349
 
 
350
/* API: Initialize the video device subsystem. */
 
351
PJ_DEF(pj_status_t) pjmedia_vid_dev_subsys_init(pj_pool_factory *pf)
 
352
{
 
353
    unsigned i;
 
354
    pj_status_t status = PJ_SUCCESS;
 
355
 
 
356
    /* Allow init() to be called multiple times as long as there is matching
 
357
     * number of shutdown().
 
358
     */
 
359
    if (vid_subsys.init_count++ != 0) {
 
360
        return PJ_SUCCESS;
 
361
    }
 
362
 
 
363
    /* Register error subsystem */
 
364
    pj_register_strerror(PJMEDIA_VIDEODEV_ERRNO_START, 
 
365
                         PJ_ERRNO_SPACE_SIZE, 
 
366
                         &pjmedia_videodev_strerror);
 
367
 
 
368
    /* Init */
 
369
    vid_subsys.pf = pf;
 
370
    vid_subsys.drv_cnt = 0;
 
371
    vid_subsys.dev_cnt = 0;
 
372
 
 
373
    /* Register creation functions */
 
374
#if PJMEDIA_VIDEO_DEV_HAS_V4L2
 
375
    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_v4l2_factory;
 
376
#endif
 
377
#if PJMEDIA_VIDEO_DEV_HAS_QT
 
378
    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_qt_factory;
 
379
#endif
 
380
#if PJMEDIA_VIDEO_DEV_HAS_IOS
 
381
    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_ios_factory;
 
382
#endif
 
383
#if PJMEDIA_VIDEO_DEV_HAS_DSHOW
 
384
    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_dshow_factory;
 
385
#endif
 
386
#if PJMEDIA_VIDEO_DEV_HAS_FFMPEG
 
387
    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_ffmpeg_factory;
 
388
#endif
 
389
#if PJMEDIA_VIDEO_DEV_HAS_CBAR_SRC
 
390
    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_cbar_factory;
 
391
#endif
 
392
#if PJMEDIA_VIDEO_DEV_HAS_SDL
 
393
    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_sdl_factory;
 
394
#endif
 
395
 
 
396
    /* Initialize each factory and build the device ID list */
 
397
    for (i=0; i<vid_subsys.drv_cnt; ++i) {
 
398
        status = init_driver(i, PJ_FALSE);
 
399
        if (status != PJ_SUCCESS) {
 
400
            deinit_driver(i);
 
401
            continue;
 
402
        }
 
403
    }
 
404
 
 
405
    return vid_subsys.dev_cnt ? PJ_SUCCESS : status;
 
406
}
 
407
 
 
408
/* API: register a video device factory to the video device subsystem. */
 
409
PJ_DEF(pj_status_t)
 
410
pjmedia_vid_register_factory(pjmedia_vid_dev_factory_create_func_ptr adf,
 
411
                             pjmedia_vid_dev_factory *factory)
 
412
{
 
413
    pj_bool_t refresh = PJ_FALSE;
 
414
    pj_status_t status;
 
415
 
 
416
    if (vid_subsys.init_count == 0)
 
417
        return PJMEDIA_EVID_INIT;
 
418
 
 
419
    vid_subsys.drv[vid_subsys.drv_cnt].create = adf;
 
420
    vid_subsys.drv[vid_subsys.drv_cnt].f = factory;
 
421
 
 
422
    if (factory) {
 
423
        /* Call factory->init() */
 
424
        status = factory->op->init(factory);
 
425
        if (status != PJ_SUCCESS) {
 
426
            factory->op->destroy(factory);
 
427
            return status;
 
428
        }
 
429
        refresh = PJ_TRUE;
 
430
    }
 
431
 
 
432
    status = init_driver(vid_subsys.drv_cnt, refresh);
 
433
    if (status == PJ_SUCCESS) {
 
434
        vid_subsys.drv_cnt++;
 
435
    } else {
 
436
        deinit_driver(vid_subsys.drv_cnt);
 
437
    }
 
438
 
 
439
    return status;
 
440
}
 
441
 
 
442
/* API: unregister a video device factory from the video device subsystem. */
 
443
PJ_DEF(pj_status_t)
 
444
pjmedia_vid_unregister_factory(pjmedia_vid_dev_factory_create_func_ptr adf,
 
445
                               pjmedia_vid_dev_factory *factory)
 
446
{
 
447
    unsigned i, j;
 
448
 
 
449
    if (vid_subsys.init_count == 0)
 
450
        return PJMEDIA_EVID_INIT;
 
451
 
 
452
    for (i=0; i<vid_subsys.drv_cnt; ++i) {
 
453
        struct driver *drv = &vid_subsys.drv[i];
 
454
 
 
455
        if ((factory && drv->f==factory) || (adf && drv->create == adf)) {
 
456
            for (j = drv->start_idx; j < drv->start_idx + drv->dev_cnt; j++)
 
457
            {
 
458
                vid_subsys.dev_list[j] = (pj_uint32_t)PJMEDIA_VID_INVALID_DEV;
 
459
            }
 
460
 
 
461
            deinit_driver(i);
 
462
            pj_bzero(drv, sizeof(*drv));
 
463
            return PJ_SUCCESS;
 
464
        }
 
465
    }
 
466
 
 
467
    return PJMEDIA_EVID_ERR;
 
468
}
 
469
 
 
470
/* API: get the pool factory registered to the video device subsystem. */
 
471
PJ_DEF(pj_pool_factory*) pjmedia_vid_dev_subsys_get_pool_factory(void)
 
472
{
 
473
    return vid_subsys.pf;
 
474
}
 
475
 
 
476
/* API: Shutdown the video device subsystem. */
 
477
PJ_DEF(pj_status_t) pjmedia_vid_dev_subsys_shutdown(void)
 
478
{
 
479
    unsigned i;
 
480
 
 
481
    /* Allow shutdown() to be called multiple times as long as there is
 
482
     * matching number of init().
 
483
     */
 
484
    if (vid_subsys.init_count == 0) {
 
485
        return PJ_SUCCESS;
 
486
    }
 
487
    --vid_subsys.init_count;
 
488
 
 
489
    if (vid_subsys.init_count == 0) {
 
490
        for (i=0; i<vid_subsys.drv_cnt; ++i) {
 
491
            deinit_driver(i);
 
492
        }
 
493
 
 
494
        vid_subsys.pf = NULL;
 
495
    }
 
496
    return PJ_SUCCESS;
 
497
}
 
498
 
 
499
/* API: Refresh the list of video devices installed in the system. */
 
500
PJ_DEF(pj_status_t) pjmedia_vid_dev_refresh(void)
 
501
{
 
502
    unsigned i;
 
503
    
 
504
    vid_subsys.dev_cnt = 0;
 
505
    for (i=0; i<vid_subsys.drv_cnt; ++i) {
 
506
        struct driver *drv = &vid_subsys.drv[i];
 
507
        
 
508
        if (drv->f && drv->f->op->refresh) {
 
509
            pj_status_t status = drv->f->op->refresh(drv->f);
 
510
            if (status != PJ_SUCCESS) {
 
511
                PJ_PERROR(4, (THIS_FILE, status, "Unable to refresh device "
 
512
                                                 "list for %s", drv->name));
 
513
            }
 
514
        }
 
515
        init_driver(i, PJ_TRUE);
 
516
    }
 
517
    return PJ_SUCCESS;
 
518
}
 
519
 
 
520
/* API: Get the number of video devices installed in the system. */
 
521
PJ_DEF(unsigned) pjmedia_vid_dev_count(void)
 
522
{
 
523
    return vid_subsys.dev_cnt;
 
524
}
 
525
 
 
526
/* Internal: convert local index to global device index */
 
527
static pj_status_t make_global_index(unsigned drv_idx, 
 
528
                                     pjmedia_vid_dev_index *id)
 
529
{
 
530
    if (*id < 0) {
 
531
        return PJ_SUCCESS;
 
532
    }
 
533
 
 
534
    /* Check that factory still exists */
 
535
    PJ_ASSERT_RETURN(vid_subsys.drv[drv_idx].f, PJ_EBUG);
 
536
 
 
537
    /* Check that device index is valid */
 
538
    PJ_ASSERT_RETURN(*id>=0 && *id<(int)vid_subsys.drv[drv_idx].dev_cnt, 
 
539
                     PJ_EBUG);
 
540
 
 
541
    *id += vid_subsys.drv[drv_idx].start_idx;
 
542
    return PJ_SUCCESS;
 
543
}
 
544
 
 
545
/* Internal: lookup device id */
 
546
static pj_status_t lookup_dev(pjmedia_vid_dev_index id,
 
547
                              pjmedia_vid_dev_factory **p_f,
 
548
                              unsigned *p_local_index)
 
549
{
 
550
    int f_id, index;
 
551
 
 
552
    if (id < 0) {
 
553
        unsigned i;
 
554
 
 
555
        if (id <= PJMEDIA_VID_INVALID_DEV)
 
556
            return PJMEDIA_EVID_INVDEV;
 
557
 
 
558
        for (i=0; i<vid_subsys.drv_cnt; ++i) {
 
559
            struct driver *drv = &vid_subsys.drv[i];
 
560
            if (id==PJMEDIA_VID_DEFAULT_CAPTURE_DEV && 
 
561
                drv->cap_dev_idx >= 0) 
 
562
            {
 
563
                id = drv->cap_dev_idx;
 
564
                make_global_index(i, &id);
 
565
                break;
 
566
            } else if (id==PJMEDIA_VID_DEFAULT_RENDER_DEV && 
 
567
                drv->rend_dev_idx >= 0) 
 
568
            {
 
569
                id = drv->rend_dev_idx;
 
570
                make_global_index(i, &id);
 
571
                break;
 
572
            }
 
573
        }
 
574
 
 
575
        if (id < 0) {
 
576
            return PJMEDIA_EVID_NODEFDEV;
 
577
        }
 
578
    }
 
579
 
 
580
    f_id = GET_FID(vid_subsys.dev_list[id]);
 
581
    index = GET_INDEX(vid_subsys.dev_list[id]);
 
582
 
 
583
    if (f_id < 0 || f_id >= (int)vid_subsys.drv_cnt)
 
584
        return PJMEDIA_EVID_INVDEV;
 
585
 
 
586
    if (index < 0 || index >= (int)vid_subsys.drv[f_id].dev_cnt)
 
587
        return PJMEDIA_EVID_INVDEV;
 
588
 
 
589
    *p_f = vid_subsys.drv[f_id].f;
 
590
    *p_local_index = (unsigned)index;
 
591
 
 
592
    return PJ_SUCCESS;
 
593
 
 
594
}
 
595
 
 
596
/* API: lookup device id */
 
597
PJ_DEF(pj_status_t)
 
598
pjmedia_vid_dev_get_local_index(pjmedia_vid_dev_index id,
 
599
                                pjmedia_vid_dev_factory **p_f,
 
600
                                unsigned *p_local_index)
 
601
{
 
602
    return lookup_dev(id, p_f, p_local_index);
 
603
}
 
604
 
 
605
/* API: from factory and local index, get global index */
 
606
PJ_DEF(pj_status_t)
 
607
pjmedia_vid_dev_get_global_index(const pjmedia_vid_dev_factory *f,
 
608
                                 unsigned local_idx,
 
609
                                 pjmedia_vid_dev_index *pid)
 
610
{
 
611
    PJ_ASSERT_RETURN(f->sys.drv_idx >= 0 && f->sys.drv_idx < MAX_DRIVERS,
 
612
                     PJ_EINVALIDOP);
 
613
    *pid = local_idx;
 
614
    return make_global_index(f->sys.drv_idx, pid);
 
615
}
 
616
 
 
617
/* API: Get device information. */
 
618
PJ_DEF(pj_status_t) pjmedia_vid_dev_get_info(pjmedia_vid_dev_index id,
 
619
                                             pjmedia_vid_dev_info *info)
 
620
{
 
621
    pjmedia_vid_dev_factory *f;
 
622
    unsigned index;
 
623
    pj_status_t status;
 
624
 
 
625
    PJ_ASSERT_RETURN(info, PJ_EINVAL);
 
626
    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
 
627
 
 
628
    if (id <= PJMEDIA_VID_INVALID_DEV)
 
629
        return PJMEDIA_EVID_INVDEV;
 
630
 
 
631
    status = lookup_dev(id, &f, &index);
 
632
    if (status != PJ_SUCCESS)
 
633
        return status;
 
634
 
 
635
    status = f->op->get_dev_info(f, index, info);
 
636
 
 
637
    /* Make sure device ID is the real ID (not PJMEDIA_VID_DEFAULT_*_DEV) */
 
638
    info->id = index;
 
639
    make_global_index(f->sys.drv_idx, &info->id);
 
640
 
 
641
    return status;
 
642
}
 
643
 
 
644
/* API: find device */
 
645
PJ_DEF(pj_status_t) pjmedia_vid_dev_lookup( const char *drv_name,
 
646
                                            const char *dev_name,
 
647
                                            pjmedia_vid_dev_index *id)
 
648
{
 
649
    pjmedia_vid_dev_factory *f = NULL;
 
650
    unsigned drv_idx, dev_idx;
 
651
 
 
652
    PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);
 
653
    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
 
654
 
 
655
    for (drv_idx=0; drv_idx<vid_subsys.drv_cnt; ++drv_idx) {
 
656
        if (!pj_ansi_stricmp(drv_name, vid_subsys.drv[drv_idx].name))
 
657
        {
 
658
            f = vid_subsys.drv[drv_idx].f;
 
659
            break;
 
660
        }
 
661
    }
 
662
 
 
663
    if (!f)
 
664
        return PJ_ENOTFOUND;
 
665
 
 
666
    for (dev_idx=0; dev_idx<vid_subsys.drv[drv_idx].dev_cnt; ++dev_idx)
 
667
    {
 
668
        pjmedia_vid_dev_info info;
 
669
        pj_status_t status;
 
670
 
 
671
        status = f->op->get_dev_info(f, dev_idx, &info);
 
672
        if (status != PJ_SUCCESS)
 
673
            return status;
 
674
 
 
675
        if (!pj_ansi_stricmp(dev_name, info.name))
 
676
            break;
 
677
    }
 
678
 
 
679
    if (dev_idx==vid_subsys.drv[drv_idx].dev_cnt)
 
680
        return PJ_ENOTFOUND;
 
681
 
 
682
    *id = dev_idx;
 
683
    make_global_index(drv_idx, id);
 
684
 
 
685
    return PJ_SUCCESS;
 
686
}
 
687
 
 
688
/* API: Initialize the video device parameters with default values for the
 
689
 * specified device.
 
690
 */
 
691
PJ_DEF(pj_status_t) pjmedia_vid_dev_default_param(pj_pool_t *pool,
 
692
                                                  pjmedia_vid_dev_index id,
 
693
                                                  pjmedia_vid_dev_param *param)
 
694
{
 
695
    pjmedia_vid_dev_factory *f;
 
696
    unsigned index;
 
697
    pj_status_t status;
 
698
 
 
699
    PJ_ASSERT_RETURN(param, PJ_EINVAL);
 
700
    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
 
701
 
 
702
    if (id <= PJMEDIA_VID_INVALID_DEV)
 
703
        return PJMEDIA_EVID_INVDEV;
 
704
 
 
705
    status = lookup_dev(id, &f, &index);
 
706
    if (status != PJ_SUCCESS)
 
707
        return status;
 
708
 
 
709
    status = f->op->default_param(pool, f, index, param);
 
710
    if (status != PJ_SUCCESS)
 
711
        return status;
 
712
 
 
713
    /* Normalize device IDs */
 
714
    make_global_index(f->sys.drv_idx, &param->cap_id);
 
715
    make_global_index(f->sys.drv_idx, &param->rend_id);
 
716
 
 
717
    return PJ_SUCCESS;
 
718
}
 
719
 
 
720
/* API: Open video stream object using the specified parameters. */
 
721
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_create(
 
722
                                        pjmedia_vid_dev_param *prm,
 
723
                                        const pjmedia_vid_dev_cb *cb,
 
724
                                        void *user_data,
 
725
                                        pjmedia_vid_dev_stream **p_vid_strm)
 
726
{
 
727
    pjmedia_vid_dev_factory *cap_f=NULL, *rend_f=NULL, *f=NULL;
 
728
    pj_status_t status;
 
729
 
 
730
    PJ_ASSERT_RETURN(prm && prm->dir && p_vid_strm, PJ_EINVAL);
 
731
    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
 
732
    PJ_ASSERT_RETURN(prm->dir==PJMEDIA_DIR_CAPTURE ||
 
733
                     prm->dir==PJMEDIA_DIR_RENDER ||
 
734
                     prm->dir==PJMEDIA_DIR_CAPTURE_RENDER,
 
735
                     PJ_EINVAL);
 
736
 
 
737
    /* Normalize cap_id */
 
738
    if (prm->dir & PJMEDIA_DIR_CAPTURE) {
 
739
        unsigned index;
 
740
 
 
741
        if (prm->cap_id < 0)
 
742
            prm->cap_id = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
 
743
 
 
744
        status = lookup_dev(prm->cap_id, &cap_f, &index);
 
745
        if (status != PJ_SUCCESS)
 
746
            return status;
 
747
 
 
748
        prm->cap_id = index;
 
749
        f = cap_f;
 
750
    }
 
751
 
 
752
    /* Normalize rend_id */
 
753
    if (prm->dir & PJMEDIA_DIR_RENDER) {
 
754
        unsigned index;
 
755
 
 
756
        if (prm->rend_id < 0)
 
757
            prm->rend_id = PJMEDIA_VID_DEFAULT_RENDER_DEV;
 
758
 
 
759
        status = lookup_dev(prm->rend_id, &rend_f, &index);
 
760
        if (status != PJ_SUCCESS)
 
761
            return status;
 
762
 
 
763
        prm->rend_id = index;
 
764
        f = rend_f;
 
765
    }
 
766
 
 
767
    PJ_ASSERT_RETURN(f != NULL, PJ_EBUG);
 
768
 
 
769
    /* For now, cap_id and rend_id must belong to the same factory */
 
770
    PJ_ASSERT_RETURN((prm->dir != PJMEDIA_DIR_CAPTURE_RENDER) ||
 
771
                     (cap_f == rend_f),
 
772
                     PJMEDIA_EVID_INVDEV);
 
773
 
 
774
    /* Create the stream */
 
775
    status = f->op->create_stream(f, prm, cb,
 
776
                                  user_data, p_vid_strm);
 
777
    if (status != PJ_SUCCESS)
 
778
        return status;
 
779
 
 
780
    /* Assign factory id to the stream */
 
781
    (*p_vid_strm)->sys.drv_idx = f->sys.drv_idx;
 
782
    return PJ_SUCCESS;
 
783
}
 
784
 
 
785
/* API: Get the running parameters for the specified video stream. */
 
786
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_param(
 
787
                                            pjmedia_vid_dev_stream *strm,
 
788
                                            pjmedia_vid_dev_param *param)
 
789
{
 
790
    pj_status_t status;
 
791
 
 
792
    PJ_ASSERT_RETURN(strm && param, PJ_EINVAL);
 
793
    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
 
794
 
 
795
    status = strm->op->get_param(strm, param);
 
796
    if (status != PJ_SUCCESS)
 
797
        return status;
 
798
 
 
799
    /* Normalize device id's */
 
800
    make_global_index(strm->sys.drv_idx, &param->cap_id);
 
801
    make_global_index(strm->sys.drv_idx, &param->rend_id);
 
802
 
 
803
    return PJ_SUCCESS;
 
804
}
 
805
 
 
806
/* API: Get the value of a specific capability of the video stream. */
 
807
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_cap(
 
808
                                            pjmedia_vid_dev_stream *strm,
 
809
                                            pjmedia_vid_dev_cap cap,
 
810
                                            void *value)
 
811
{
 
812
    return strm->op->get_cap(strm, cap, value);
 
813
}
 
814
 
 
815
/* API: Set the value of a specific capability of the video stream. */
 
816
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_set_cap(
 
817
                                            pjmedia_vid_dev_stream *strm,
 
818
                                            pjmedia_vid_dev_cap cap,
 
819
                                            const void *value)
 
820
{
 
821
    return strm->op->set_cap(strm, cap, value);
 
822
}
 
823
 
 
824
/* API: Start the stream. */
 
825
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_start(pjmedia_vid_dev_stream *strm)
 
826
{
 
827
    pj_status_t status;
 
828
 
 
829
    if (pjmedia_vid_dev_stream_is_running(strm))
 
830
        return PJ_SUCCESS;
 
831
 
 
832
    status = strm->op->start(strm);
 
833
    if (status == PJ_SUCCESS)
 
834
        strm->sys.is_running = PJ_TRUE;
 
835
    return status;
 
836
}
 
837
 
 
838
/* API: has it been started? */
 
839
PJ_DEF(pj_bool_t)
 
840
pjmedia_vid_dev_stream_is_running(pjmedia_vid_dev_stream *strm)
 
841
{
 
842
    return strm->sys.is_running;
 
843
}
 
844
 
 
845
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_frame(
 
846
                                            pjmedia_vid_dev_stream *strm,
 
847
                                            pjmedia_frame *frame)
 
848
{
 
849
    pj_assert(strm->op->get_frame);
 
850
    return strm->op->get_frame(strm, frame);
 
851
}
 
852
 
 
853
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_put_frame(
 
854
                                            pjmedia_vid_dev_stream *strm,
 
855
                                            const pjmedia_frame *frame)
 
856
{
 
857
    pj_assert(strm->op->put_frame);
 
858
    return strm->op->put_frame(strm, frame);
 
859
}
 
860
 
 
861
/* API: Stop the stream. */
 
862
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_stop(pjmedia_vid_dev_stream *strm)
 
863
{
 
864
    strm->sys.is_running = PJ_FALSE;
 
865
    return strm->op->stop(strm);
 
866
}
 
867
 
 
868
/* API: Destroy the stream. */
 
869
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_destroy(
 
870
                                                pjmedia_vid_dev_stream *strm)
 
871
{
 
872
    strm->sys.is_running = PJ_FALSE;
 
873
    return strm->op->destroy(strm);
 
874
}
 
875
 
 
876
 
 
877
#endif /* PJMEDIA_HAS_VIDEO */