~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* 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: vid_tee.c 3773 2011-09-23 04:06:01Z nanang $ */
 
2
/* 
 
3
 * Copyright (C) 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/vid_tee.h>
 
20
#include <pjmedia/converter.h>
 
21
#include <pjmedia/errno.h>
 
22
#include <pj/array.h>
 
23
#include <pj/log.h>
 
24
#include <pj/pool.h>
 
25
 
 
26
 
 
27
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
 
28
 
 
29
 
 
30
#define TEE_PORT_NAME   "vid_tee"
 
31
#define TEE_PORT_SIGN   PJMEDIA_SIG_PORT_VID_TEE
 
32
 
 
33
#define THIS_FILE       "vid_tee.c"
 
34
 
 
35
typedef struct vid_tee_dst_port
 
36
{
 
37
    pjmedia_port        *dst;
 
38
    unsigned             option;
 
39
} vid_tee_dst_port;
 
40
 
 
41
 
 
42
typedef struct vid_tee_port
 
43
{
 
44
    pjmedia_port         base;
 
45
    pj_pool_t           *pool;
 
46
    pj_pool_factory     *pf;
 
47
    pj_pool_t           *buf_pool;
 
48
    void                *buf[2];
 
49
    unsigned             buf_cnt;
 
50
    pj_size_t            buf_size;
 
51
    unsigned             dst_port_maxcnt;
 
52
    unsigned             dst_port_cnt;
 
53
    vid_tee_dst_port    *dst_ports;
 
54
    pj_uint8_t          *put_frm_flag;
 
55
    
 
56
    struct vid_tee_conv_t {
 
57
        pjmedia_converter   *conv;
 
58
        pj_size_t            conv_buf_size;        
 
59
    } *tee_conv;
 
60
} vid_tee_port;
 
61
 
 
62
 
 
63
static pj_status_t tee_put_frame(pjmedia_port *port, pjmedia_frame *frame);
 
64
static pj_status_t tee_get_frame(pjmedia_port *port, pjmedia_frame *frame);
 
65
static pj_status_t tee_destroy(pjmedia_port *port);
 
66
 
 
67
/*
 
68
 * Create a video tee port with the specified source media port.
 
69
 */
 
70
PJ_DEF(pj_status_t) pjmedia_vid_tee_create( pj_pool_t *pool,
 
71
                                            const pjmedia_format *fmt,
 
72
                                            unsigned max_dst_cnt,
 
73
                                            pjmedia_port **p_vid_tee)
 
74
{
 
75
    vid_tee_port *tee;
 
76
    pj_str_t name_st;
 
77
    const pjmedia_video_format_info *vfi;
 
78
    pjmedia_video_apply_fmt_param vafp;
 
79
    pj_status_t status;
 
80
 
 
81
    PJ_ASSERT_RETURN(pool && fmt && p_vid_tee, PJ_EINVAL);
 
82
    PJ_ASSERT_RETURN(fmt->type == PJMEDIA_TYPE_VIDEO, PJ_EINVAL);
 
83
 
 
84
    /* Allocate video tee structure */
 
85
    tee = PJ_POOL_ZALLOC_T(pool, vid_tee_port);
 
86
    tee->pf = pool->factory;
 
87
    tee->pool = pj_pool_create(tee->pf, "video tee", 500, 500, NULL);
 
88
 
 
89
    /* Initialize video tee structure */
 
90
    tee->dst_port_maxcnt = max_dst_cnt;
 
91
    tee->dst_ports = (vid_tee_dst_port*)
 
92
                     pj_pool_calloc(pool, max_dst_cnt,
 
93
                                    sizeof(vid_tee_dst_port));
 
94
    tee->tee_conv = (struct vid_tee_conv_t *)
 
95
                    pj_pool_calloc(pool, max_dst_cnt,
 
96
                                   sizeof(struct vid_tee_conv_t));
 
97
    tee->put_frm_flag = (pj_uint8_t*)
 
98
                        pj_pool_calloc(pool, max_dst_cnt,
 
99
                                       sizeof(tee->put_frm_flag[0]));
 
100
 
 
101
    /* Initialize video tee buffer, its size is one frame */
 
102
    vfi = pjmedia_get_video_format_info(NULL, fmt->id);
 
103
    if (vfi == NULL)
 
104
        return PJMEDIA_EBADFMT;
 
105
 
 
106
    pj_bzero(&vafp, sizeof(vafp));
 
107
    vafp.size = fmt->det.vid.size;
 
108
    status = vfi->apply_fmt(vfi, &vafp);
 
109
    if (status != PJ_SUCCESS)
 
110
        return status;
 
111
 
 
112
    tee->buf_size = vafp.framebytes;
 
113
 
 
114
    /* Initialize video tee port */
 
115
    status = pjmedia_port_info_init2(&tee->base.info,
 
116
                                     pj_strset2(&name_st, (char*)TEE_PORT_NAME),
 
117
                                     TEE_PORT_SIGN,
 
118
                                     PJMEDIA_DIR_ENCODING,
 
119
                                     fmt);
 
120
    if (status != PJ_SUCCESS)
 
121
        return status;
 
122
 
 
123
    tee->base.get_frame = &tee_get_frame;
 
124
    tee->base.put_frame = &tee_put_frame;
 
125
    tee->base.on_destroy = &tee_destroy;
 
126
 
 
127
    /* Done */
 
128
    *p_vid_tee = &tee->base;
 
129
 
 
130
    return PJ_SUCCESS;
 
131
}
 
132
 
 
133
static void realloc_buf(vid_tee_port *vid_tee,
 
134
                        unsigned buf_cnt, pj_size_t buf_size)
 
135
{
 
136
    unsigned i;
 
137
    
 
138
    if (buf_cnt > vid_tee->buf_cnt)
 
139
        vid_tee->buf_cnt = buf_cnt;
 
140
    
 
141
    if (buf_size > vid_tee->buf_size) {
 
142
        /* We need a larger buffer here. */
 
143
        vid_tee->buf_size = buf_size;
 
144
        if (vid_tee->buf_pool) {
 
145
            pj_pool_release(vid_tee->buf_pool);
 
146
            vid_tee->buf_pool = NULL;
 
147
        }
 
148
        vid_tee->buf[0] = vid_tee->buf[1] = NULL;
 
149
    }
 
150
    
 
151
    if (!vid_tee->buf_pool) {
 
152
        vid_tee->buf_pool = pj_pool_create(vid_tee->pf, "video tee buffer",
 
153
                                           1000, 1000, NULL);
 
154
    }
 
155
 
 
156
    for (i = 0; i < vid_tee->buf_cnt; i++) {
 
157
        if (!vid_tee->buf[i])
 
158
            vid_tee->buf[i] = pj_pool_alloc(vid_tee->buf_pool,
 
159
                                            vid_tee->buf_size);
 
160
    }
 
161
}
 
162
 
 
163
/*
 
164
 * Add a destination media port to the video tee.
 
165
 */
 
166
PJ_DEF(pj_status_t) pjmedia_vid_tee_add_dst_port(pjmedia_port *vid_tee,
 
167
                                                 unsigned option,
 
168
                                                 pjmedia_port *port)
 
169
{
 
170
    vid_tee_port *tee = (vid_tee_port*)vid_tee;
 
171
    pjmedia_video_format_detail *vfd;
 
172
 
 
173
    PJ_ASSERT_RETURN(vid_tee && vid_tee->info.signature==TEE_PORT_SIGN,
 
174
                     PJ_EINVAL);
 
175
 
 
176
    if (tee->dst_port_cnt >= tee->dst_port_maxcnt)
 
177
        return PJ_ETOOMANY;
 
178
    
 
179
    if (vid_tee->info.fmt.id != port->info.fmt.id)
 
180
        return PJMEDIA_EBADFMT;
 
181
 
 
182
    vfd = pjmedia_format_get_video_format_detail(&port->info.fmt, PJ_TRUE);
 
183
    if (vfd->size.w != vid_tee->info.fmt.det.vid.size.w ||
 
184
        vfd->size.h != vid_tee->info.fmt.det.vid.size.h)
 
185
    {
 
186
        return PJMEDIA_EBADFMT;
 
187
    }
 
188
    
 
189
    realloc_buf(tee, (option & PJMEDIA_VID_TEE_DST_DO_IN_PLACE_PROC)?
 
190
                1: 0, tee->buf_size);
 
191
 
 
192
    pj_bzero(&tee->tee_conv[tee->dst_port_cnt], sizeof(tee->tee_conv[0]));
 
193
    tee->dst_ports[tee->dst_port_cnt].dst = port;
 
194
    tee->dst_ports[tee->dst_port_cnt].option = option;
 
195
    ++tee->dst_port_cnt;
 
196
 
 
197
    return PJ_SUCCESS;
 
198
}
 
199
 
 
200
 
 
201
/*
 
202
 * Add a destination media port to the video tee. Create a converter if
 
203
 * necessary.
 
204
 */
 
205
PJ_DEF(pj_status_t) pjmedia_vid_tee_add_dst_port2(pjmedia_port *vid_tee,
 
206
                                                  unsigned option,
 
207
                                                  pjmedia_port *port)
 
208
{
 
209
    vid_tee_port *tee = (vid_tee_port*)vid_tee;
 
210
    pjmedia_video_format_detail *vfd;
 
211
    
 
212
    PJ_ASSERT_RETURN(vid_tee && vid_tee->info.signature==TEE_PORT_SIGN,
 
213
                     PJ_EINVAL);
 
214
    
 
215
    if (tee->dst_port_cnt >= tee->dst_port_maxcnt)
 
216
        return PJ_ETOOMANY;
 
217
    
 
218
    pj_bzero(&tee->tee_conv[tee->dst_port_cnt], sizeof(tee->tee_conv[0]));
 
219
    
 
220
    /* Check if we need to create a converter. */
 
221
    vfd = pjmedia_format_get_video_format_detail(&port->info.fmt, PJ_TRUE);
 
222
    if (vid_tee->info.fmt.id != port->info.fmt.id ||
 
223
        vfd->size.w != vid_tee->info.fmt.det.vid.size.w ||
 
224
        vfd->size.h != vid_tee->info.fmt.det.vid.size.h)
 
225
    {
 
226
        const pjmedia_video_format_info *vfi;
 
227
        pjmedia_video_apply_fmt_param vafp;
 
228
        pjmedia_conversion_param conv_param;
 
229
        pj_status_t status;
 
230
 
 
231
        vfi = pjmedia_get_video_format_info(NULL, port->info.fmt.id);
 
232
        if (vfi == NULL)
 
233
            return PJMEDIA_EBADFMT;
 
234
 
 
235
        pj_bzero(&vafp, sizeof(vafp));
 
236
        vafp.size = port->info.fmt.det.vid.size;
 
237
        status = vfi->apply_fmt(vfi, &vafp);
 
238
        if (status != PJ_SUCCESS)
 
239
            return status;
 
240
        
 
241
        realloc_buf(tee, (option & PJMEDIA_VID_TEE_DST_DO_IN_PLACE_PROC)?
 
242
                    2: 1, vafp.framebytes);
 
243
        
 
244
        pjmedia_format_copy(&conv_param.src, &vid_tee->info.fmt);
 
245
        pjmedia_format_copy(&conv_param.dst, &port->info.fmt);
 
246
        
 
247
        status = pjmedia_converter_create(
 
248
                     NULL, tee->pool, &conv_param,
 
249
                     &tee->tee_conv[tee->dst_port_cnt].conv);
 
250
        if (status != PJ_SUCCESS)
 
251
            return status;
 
252
        
 
253
        tee->tee_conv[tee->dst_port_cnt].conv_buf_size = vafp.framebytes;
 
254
    } else {
 
255
        realloc_buf(tee, (option & PJMEDIA_VID_TEE_DST_DO_IN_PLACE_PROC)?
 
256
                    1: 0, tee->buf_size);        
 
257
    }
 
258
    
 
259
    tee->dst_ports[tee->dst_port_cnt].dst = port;
 
260
    tee->dst_ports[tee->dst_port_cnt].option = option;
 
261
    ++tee->dst_port_cnt;
 
262
    
 
263
    return PJ_SUCCESS;
 
264
}
 
265
 
 
266
 
 
267
/*
 
268
 * Remove a destination media port from the video tee.
 
269
 */
 
270
PJ_DEF(pj_status_t) pjmedia_vid_tee_remove_dst_port(pjmedia_port *vid_tee,
 
271
                                                    pjmedia_port *port)
 
272
{
 
273
    vid_tee_port *tee = (vid_tee_port*)vid_tee;
 
274
    unsigned i;
 
275
 
 
276
    PJ_ASSERT_RETURN(vid_tee && vid_tee->info.signature==TEE_PORT_SIGN,
 
277
                     PJ_EINVAL);
 
278
 
 
279
    for (i = 0; i < tee->dst_port_cnt; ++i) {
 
280
        if (tee->dst_ports[i].dst == port) {
 
281
            if (tee->tee_conv[i].conv)
 
282
                pjmedia_converter_destroy(tee->tee_conv[i].conv);
 
283
            
 
284
            pj_array_erase(tee->dst_ports, sizeof(tee->dst_ports[0]),
 
285
                           tee->dst_port_cnt, i);
 
286
            pj_array_erase(tee->tee_conv, sizeof(tee->tee_conv[0]),
 
287
                           tee->dst_port_cnt, i);
 
288
            --tee->dst_port_cnt;
 
289
            return PJ_SUCCESS;
 
290
        }
 
291
    }
 
292
 
 
293
    return PJ_ENOTFOUND;
 
294
}
 
295
 
 
296
 
 
297
static pj_status_t tee_put_frame(pjmedia_port *port, pjmedia_frame *frame)
 
298
{
 
299
    vid_tee_port *tee = (vid_tee_port*)port;
 
300
    unsigned i, j;
 
301
    const pj_uint8_t PUT_FRM_DONE = 1;
 
302
 
 
303
    pj_bzero(tee->put_frm_flag, tee->dst_port_cnt *
 
304
                                sizeof(tee->put_frm_flag[0]));
 
305
 
 
306
    for (i = 0; i < tee->dst_port_cnt; ++i) {
 
307
        pjmedia_frame frame_ = *frame;
 
308
 
 
309
        if (tee->put_frm_flag[i])
 
310
            continue;
 
311
        
 
312
        if (tee->tee_conv[i].conv) {
 
313
            pj_status_t status;
 
314
            
 
315
            frame_.buf  = tee->buf[0];
 
316
            frame_.size = tee->tee_conv[i].conv_buf_size;
 
317
            status = pjmedia_converter_convert(tee->tee_conv[i].conv,
 
318
                                               frame, &frame_);
 
319
            if (status != PJ_SUCCESS) {
 
320
                PJ_LOG(3, (THIS_FILE,
 
321
                               "Failed to convert frame for destination"
 
322
                               " port %d (%.*s)", i,
 
323
                               tee->dst_ports[i].dst->info.name.slen,
 
324
                               tee->dst_ports[i].dst->info.name.ptr));
 
325
                continue;
 
326
            }
 
327
        }
 
328
        
 
329
        /* Find other destination ports which has the same format so
 
330
         * we don't need to do the same conversion twice.
 
331
         */
 
332
        for (j = i; j < tee->dst_port_cnt; ++j) {
 
333
            pjmedia_frame framep;
 
334
            
 
335
            if (tee->put_frm_flag[j] ||
 
336
                (tee->dst_ports[j].dst->info.fmt.id != 
 
337
                 tee->dst_ports[i].dst->info.fmt.id) ||
 
338
                (tee->dst_ports[j].dst->info.fmt.det.vid.size.w != 
 
339
                 tee->dst_ports[i].dst->info.fmt.det.vid.size.w) ||
 
340
                (tee->dst_ports[j].dst->info.fmt.det.vid.size.h != 
 
341
                 tee->dst_ports[i].dst->info.fmt.det.vid.size.h))
 
342
            {
 
343
                continue;
 
344
            }
 
345
            
 
346
            framep = frame_;
 
347
            /* For dst_ports that do in-place processing, we need to duplicate
 
348
             * the data source first.
 
349
             */
 
350
            if (tee->dst_ports[j].option & PJMEDIA_VID_TEE_DST_DO_IN_PLACE_PROC)
 
351
            {
 
352
                PJ_ASSERT_RETURN(tee->buf_size <= frame_.size, PJ_ETOOBIG);
 
353
                framep.buf = tee->buf[tee->buf_cnt-1];
 
354
                framep.size = frame_.size;
 
355
                pj_memcpy(framep.buf, frame_.buf, frame_.size);
 
356
            }
 
357
 
 
358
            /* Deliver the data */
 
359
            pjmedia_port_put_frame(tee->dst_ports[j].dst, &framep);
 
360
            tee->put_frm_flag[j] = PUT_FRM_DONE;
 
361
            
 
362
            if (!tee->tee_conv[i].conv)
 
363
                break;
 
364
        }
 
365
    }
 
366
 
 
367
    return PJ_SUCCESS;
 
368
}
 
369
 
 
370
static pj_status_t tee_get_frame(pjmedia_port *port, pjmedia_frame *frame)
 
371
{
 
372
    PJ_UNUSED_ARG(port);
 
373
    PJ_UNUSED_ARG(frame);
 
374
 
 
375
    pj_assert(!"Bug! Tee port get_frame() shouldn't be called.");
 
376
 
 
377
    return PJ_EBUG;
 
378
}
 
379
 
 
380
static pj_status_t tee_destroy(pjmedia_port *port)
 
381
{
 
382
    vid_tee_port *tee = (vid_tee_port*)port;
 
383
 
 
384
    PJ_ASSERT_RETURN(port && port->info.signature==TEE_PORT_SIGN, PJ_EINVAL);
 
385
 
 
386
    pj_pool_release(tee->pool);
 
387
    if (tee->buf_pool)
 
388
        pj_pool_release(tee->buf_pool);
 
389
                    
 
390
    pj_bzero(tee, sizeof(*tee));
 
391
 
 
392
    return PJ_SUCCESS;
 
393
}
 
394
 
 
395
 
 
396
#endif /* PJMEDIA_HAS_VIDEO */