Changeset 3620


Ignore:
Timestamp:
Jul 12, 2011 7:14:32 AM (13 years ago)
Author:
ming
Message:

Closed #1261: Video tee

  • Add API pjmedia_vid_tee_add_dst_port2() for adding destination port which may need format conversion
Location:
pjproject/branches/projects/2.0-dev/pjmedia
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/vid_tee.h

    r3616 r3620  
    4242 * to destination ports only. Also, the video source port MUST actively call 
    4343 * pjmedia_port_put_frame() to the video tee and the video destination ports 
    44  * MUST NEVER call pjmedia_port_get_frame() to the video tee. 
     44 * MUST NEVER call pjmedia_port_get_frame() to the video tee. Please note that 
     45 * there is no specific order of which destination port will receive a frame 
     46 * from the video tee. 
    4547 * 
    4648 * The video tee is not thread-safe, so it is application responsibility 
     
    8789 
    8890/** 
    89  * Add a destination media port to the video tee. 
     91 * Add a destination media port to the video tee. For this function, the 
     92 * destination port's media format must match the source format. 
    9093 * 
    9194 * @param vid_tee           The video tee. 
     
    99102                                                  unsigned option, 
    100103                                                  pjmedia_port *port); 
     104 
     105 
     106/** 
     107 * Add a destination media port to the video tee. This function will also 
     108 * create a converter if the destination port's media format does not match 
     109 * the source format. 
     110 * 
     111 * @param vid_tee           The video tee. 
     112 * @param option            Video tee option, see @pjmedia_vid_tee_flag. 
     113 * @param port              The destination media port. 
     114 * 
     115 * @return                  PJ_SUCCESS on success, or the appropriate error 
     116 *                          code. 
     117 */ 
     118PJ_DECL(pj_status_t) pjmedia_vid_tee_add_dst_port2(pjmedia_port *vid_tee, 
     119                                                   unsigned option, 
     120                                                   pjmedia_port *port); 
    101121 
    102122 
  • pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/vid_tee.c

    r3616 r3620  
    1818 */ 
    1919#include <pjmedia/vid_tee.h> 
     20#include <pjmedia/converter.h> 
    2021#include <pjmedia/errno.h> 
    2122#include <pj/array.h> 
     23#include <pj/log.h> 
    2224#include <pj/pool.h> 
    2325 
    2426#define TEE_PORT_NAME   "vid_tee" 
    2527#define TEE_PORT_SIGN   PJMEDIA_PORT_SIGNATURE('V', 'T', 'E', 'E') 
     28#define MAX_DST_PORT_COUNT 20 
    2629 
    2730 
     
    3639{ 
    3740    pjmedia_port         base; 
    38     void                *buf; 
     41    pj_pool_t           *pool; 
     42    pj_pool_factory     *pf; 
     43    pj_pool_t           *buf_pool; 
     44    void                *buf[2]; 
     45    unsigned             buf_cnt; 
    3946    pj_size_t            buf_size; 
    4047    unsigned             dst_port_maxcnt; 
    4148    unsigned             dst_port_cnt; 
    4249    vid_tee_dst_port    *dst_ports; 
     50     
     51    struct vid_tee_conv_t { 
     52        pjmedia_converter   *conv; 
     53        pj_size_t            conv_buf_size;         
     54    } *tee_conv; 
    4355} vid_tee_port; 
    4456 
     
    6476    PJ_ASSERT_RETURN(pool && fmt && p_vid_tee, PJ_EINVAL); 
    6577    PJ_ASSERT_RETURN(fmt->type == PJMEDIA_TYPE_VIDEO, PJ_EINVAL); 
     78    PJ_ASSERT_RETURN(max_dst_cnt <= MAX_DST_PORT_COUNT, PJ_ETOOMANY); 
    6679 
    6780    /* Allocate video tee structure */ 
    6881    tee = PJ_POOL_ZALLOC_T(pool, vid_tee_port); 
     82    tee->pf = pool->factory; 
     83    tee->pool = pj_pool_create(tee->pf, "video tee", 500, 500, NULL); 
    6984 
    7085    /* Initialize video tee structure */ 
     
    7388                     pj_pool_calloc(pool, max_dst_cnt, 
    7489                                    sizeof(vid_tee_dst_port)); 
     90    tee->tee_conv = (struct vid_tee_conv_t *) 
     91                    pj_pool_calloc(pool, max_dst_cnt, 
     92                                   sizeof(struct vid_tee_conv_t)); 
    7593 
    7694    /* Initialize video tee buffer, its size is one frame */ 
     
    86104 
    87105    tee->buf_size = vafp.framebytes; 
    88     tee->buf = pj_pool_zalloc(pool, tee->buf_size); 
    89106 
    90107    /* Initialize video tee port */ 
     
    107124} 
    108125 
     126static void realloc_buf(vid_tee_port *vid_tee, 
     127                        unsigned buf_cnt, pj_size_t buf_size) 
     128{ 
     129    unsigned i; 
     130     
     131    if (buf_cnt > vid_tee->buf_cnt) 
     132        vid_tee->buf_cnt = buf_cnt; 
     133     
     134    if (buf_size > vid_tee->buf_size) { 
     135        /* We need a larger buffer here. */ 
     136        vid_tee->buf_size = buf_size; 
     137        if (vid_tee->buf_pool) { 
     138            pj_pool_release(vid_tee->buf_pool); 
     139            vid_tee->buf_pool = NULL; 
     140        } 
     141        vid_tee->buf[0] = vid_tee->buf[1] = NULL; 
     142    } 
     143     
     144    if (!vid_tee->buf_pool) { 
     145        vid_tee->buf_pool = pj_pool_create(vid_tee->pf, "video tee buffer", 
     146                                           1000, 1000, NULL); 
     147    } 
     148  
     149    for (i = 0; i < vid_tee->buf_cnt; i++) { 
     150        if (!vid_tee->buf[i]) 
     151            vid_tee->buf[i] = pj_pool_alloc(vid_tee->buf_pool, 
     152                                            vid_tee->buf_size); 
     153    } 
     154} 
    109155 
    110156/* 
     
    123169    if (tee->dst_port_cnt >= tee->dst_port_maxcnt) 
    124170        return PJ_ETOOMANY; 
    125  
     171     
    126172    if (vid_tee->info.fmt.id != port->info.fmt.id) 
    127173        return PJMEDIA_EBADFMT; 
     
    131177        vfd->size.h != vid_tee->info.fmt.det.vid.size.h) 
    132178    { 
    133         return PJMEDIA_EBADFMT; 
    134     } 
    135  
     179        return PJMEDIA_EBADFMT; 
     180    } 
     181     
     182    realloc_buf(tee, (option & PJMEDIA_VID_TEE_DST_DO_IN_PLACE_PROC)? 
     183                1: 0, tee->buf_size); 
     184 
     185    pj_bzero(&tee->tee_conv[tee->dst_port_cnt], sizeof(tee->tee_conv[0])); 
    136186    tee->dst_ports[tee->dst_port_cnt].dst = port; 
    137187    tee->dst_ports[tee->dst_port_cnt].option = option; 
    138188    ++tee->dst_port_cnt; 
    139189 
     190    return PJ_SUCCESS; 
     191} 
     192 
     193 
     194/* 
     195 * Add a destination media port to the video tee. Create a converter if 
     196 * necessary. 
     197 */ 
     198PJ_DEF(pj_status_t) pjmedia_vid_tee_add_dst_port2(pjmedia_port *vid_tee, 
     199                                                  unsigned option, 
     200                                                  pjmedia_port *port) 
     201{ 
     202    vid_tee_port *tee = (vid_tee_port*)vid_tee; 
     203    pjmedia_video_format_detail *vfd; 
     204     
     205    PJ_ASSERT_RETURN(vid_tee && vid_tee->info.signature==TEE_PORT_SIGN, 
     206                     PJ_EINVAL); 
     207     
     208    if (tee->dst_port_cnt >= tee->dst_port_maxcnt) 
     209        return PJ_ETOOMANY; 
     210     
     211    pj_bzero(&tee->tee_conv[tee->dst_port_cnt], sizeof(tee->tee_conv[0])); 
     212     
     213    /* Check if we need to create a converter. */ 
     214    vfd = pjmedia_format_get_video_format_detail(&port->info.fmt, PJ_TRUE); 
     215    if (vid_tee->info.fmt.id != port->info.fmt.id || 
     216        vfd->size.w != vid_tee->info.fmt.det.vid.size.w || 
     217        vfd->size.h != vid_tee->info.fmt.det.vid.size.h) 
     218    { 
     219        const pjmedia_video_format_info *vfi; 
     220        pjmedia_video_apply_fmt_param vafp; 
     221        pjmedia_conversion_param conv_param; 
     222        pj_status_t status; 
     223 
     224        vfi = pjmedia_get_video_format_info(NULL, port->info.fmt.id); 
     225        if (vfi == NULL) 
     226            return PJMEDIA_EBADFMT; 
     227 
     228        pj_bzero(&vafp, sizeof(vafp)); 
     229        vafp.size = port->info.fmt.det.vid.size; 
     230        status = vfi->apply_fmt(vfi, &vafp); 
     231        if (status != PJ_SUCCESS) 
     232            return status; 
     233         
     234        realloc_buf(tee, (option & PJMEDIA_VID_TEE_DST_DO_IN_PLACE_PROC)? 
     235                    2: 1, vafp.framebytes); 
     236         
     237        pjmedia_format_copy(&conv_param.src, &vid_tee->info.fmt); 
     238        pjmedia_format_copy(&conv_param.dst, &port->info.fmt); 
     239         
     240        status = pjmedia_converter_create( 
     241                     NULL, tee->pool, &conv_param, 
     242                     &tee->tee_conv[tee->dst_port_cnt].conv); 
     243        if (status != PJ_SUCCESS) 
     244            return status; 
     245         
     246        tee->tee_conv[tee->dst_port_cnt].conv_buf_size = vafp.framebytes; 
     247    } else { 
     248        realloc_buf(tee, (option & PJMEDIA_VID_TEE_DST_DO_IN_PLACE_PROC)? 
     249                    1: 0, tee->buf_size);         
     250    } 
     251     
     252    tee->dst_ports[tee->dst_port_cnt].dst = port; 
     253    tee->dst_ports[tee->dst_port_cnt].option = option; 
     254    ++tee->dst_port_cnt; 
     255     
    140256    return PJ_SUCCESS; 
    141257} 
     
    158274            pj_array_erase(tee->dst_ports, sizeof(tee->dst_ports[0]), 
    159275                           tee->dst_port_cnt, i); 
     276            pj_array_erase(tee->tee_conv, sizeof(tee->tee_conv[0]), 
     277                           tee->dst_port_cnt, i); 
    160278            --tee->dst_port_cnt; 
    161279            return PJ_SUCCESS; 
     
    170288{ 
    171289    vid_tee_port *tee = (vid_tee_port*)port; 
    172     unsigned i; 
     290    unsigned i, j; 
     291    pj_bool_t done[MAX_DST_PORT_COUNT]; 
     292     
     293    pj_bzero(done, sizeof(done)); 
    173294 
    174295    for (i = 0; i < tee->dst_port_cnt; ++i) { 
    175296        pjmedia_frame frame_ = *frame; 
    176297 
    177         /* For dst_ports that do in-place processing, we need to duplicate 
    178          * the data source first. 
    179          */ 
    180         if (tee->dst_ports[i].option & PJMEDIA_VID_TEE_DST_DO_IN_PLACE_PROC) { 
    181             PJ_ASSERT_RETURN(tee->buf_size <= frame->size, PJ_ETOOBIG); 
    182             frame_.buf = tee->buf; 
    183             frame_.size = frame->size; 
    184             pj_memcpy(frame_.buf, frame->buf, frame->size); 
    185         } 
    186  
    187         /* Deliver the data */ 
    188         pjmedia_port_put_frame(tee->dst_ports[i].dst, &frame_); 
     298        if (done[i]) 
     299            continue; 
     300         
     301        if (tee->tee_conv[i].conv) { 
     302            pj_status_t status; 
     303             
     304            frame_.buf  = tee->buf[0]; 
     305            frame_.size = tee->tee_conv[i].conv_buf_size; 
     306            status = pjmedia_converter_convert(tee->tee_conv[i].conv, 
     307                                               frame, &frame_); 
     308            if (status != PJ_SUCCESS) { 
     309                PJ_LOG(3, ("", "Failed to convert frame for destination" 
     310                               "port %d (%.*s)", i, 
     311                               tee->dst_ports[i].dst->info.name.slen, 
     312                               tee->dst_ports[i].dst->info.name.ptr)); 
     313                continue; 
     314            } 
     315        } 
     316         
     317        /* Find other destination ports which has the same format so 
     318         * we don't need to do the same conversion twice. 
     319         */ 
     320        for (j = i; j < tee->dst_port_cnt; ++j) { 
     321            pjmedia_frame framep; 
     322             
     323            if (done[j] || 
     324                (tee->dst_ports[j].dst->info.fmt.id !=  
     325                 tee->dst_ports[i].dst->info.fmt.id) || 
     326                (tee->dst_ports[j].dst->info.fmt.det.vid.size.w !=  
     327                 tee->dst_ports[i].dst->info.fmt.det.vid.size.w) || 
     328                (tee->dst_ports[j].dst->info.fmt.det.vid.size.h !=  
     329                 tee->dst_ports[i].dst->info.fmt.det.vid.size.h)) 
     330            { 
     331                continue; 
     332            } 
     333             
     334            framep = frame_; 
     335            /* For dst_ports that do in-place processing, we need to duplicate 
     336             * the data source first. 
     337             */ 
     338            if (tee->dst_ports[j].option & PJMEDIA_VID_TEE_DST_DO_IN_PLACE_PROC) 
     339            { 
     340                PJ_ASSERT_RETURN(tee->buf_size <= frame_.size, PJ_ETOOBIG); 
     341                framep.buf = tee->buf[tee->buf_cnt-1]; 
     342                framep.size = frame_.size; 
     343                pj_memcpy(framep.buf, frame_.buf, frame_.size); 
     344            } 
     345 
     346            /* Deliver the data */ 
     347            pjmedia_port_put_frame(tee->dst_ports[j].dst, &framep); 
     348            done[j] = PJ_TRUE; 
     349             
     350            if (!tee->tee_conv[i].conv) 
     351                break; 
     352        } 
    189353    } 
    190354 
     
    208372    PJ_ASSERT_RETURN(port && port->info.signature==TEE_PORT_SIGN, PJ_EINVAL); 
    209373 
     374    pj_pool_release(tee->pool); 
     375    if (tee->buf_pool) 
     376        pj_pool_release(tee->buf_pool); 
     377                     
    210378    pj_bzero(tee, sizeof(*tee)); 
    211379 
Note: See TracChangeset for help on using the changeset viewer.