Changeset 3620
- Timestamp:
- Jul 12, 2011 7:14:32 AM (13 years ago)
- 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 42 42 * to destination ports only. Also, the video source port MUST actively call 43 43 * 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. 45 47 * 46 48 * The video tee is not thread-safe, so it is application responsibility … … 87 89 88 90 /** 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. 90 93 * 91 94 * @param vid_tee The video tee. … … 99 102 unsigned option, 100 103 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 */ 118 PJ_DECL(pj_status_t) pjmedia_vid_tee_add_dst_port2(pjmedia_port *vid_tee, 119 unsigned option, 120 pjmedia_port *port); 101 121 102 122 -
pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/vid_tee.c
r3616 r3620 18 18 */ 19 19 #include <pjmedia/vid_tee.h> 20 #include <pjmedia/converter.h> 20 21 #include <pjmedia/errno.h> 21 22 #include <pj/array.h> 23 #include <pj/log.h> 22 24 #include <pj/pool.h> 23 25 24 26 #define TEE_PORT_NAME "vid_tee" 25 27 #define TEE_PORT_SIGN PJMEDIA_PORT_SIGNATURE('V', 'T', 'E', 'E') 28 #define MAX_DST_PORT_COUNT 20 26 29 27 30 … … 36 39 { 37 40 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; 39 46 pj_size_t buf_size; 40 47 unsigned dst_port_maxcnt; 41 48 unsigned dst_port_cnt; 42 49 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; 43 55 } vid_tee_port; 44 56 … … 64 76 PJ_ASSERT_RETURN(pool && fmt && p_vid_tee, PJ_EINVAL); 65 77 PJ_ASSERT_RETURN(fmt->type == PJMEDIA_TYPE_VIDEO, PJ_EINVAL); 78 PJ_ASSERT_RETURN(max_dst_cnt <= MAX_DST_PORT_COUNT, PJ_ETOOMANY); 66 79 67 80 /* Allocate video tee structure */ 68 81 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); 69 84 70 85 /* Initialize video tee structure */ … … 73 88 pj_pool_calloc(pool, max_dst_cnt, 74 89 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)); 75 93 76 94 /* Initialize video tee buffer, its size is one frame */ … … 86 104 87 105 tee->buf_size = vafp.framebytes; 88 tee->buf = pj_pool_zalloc(pool, tee->buf_size);89 106 90 107 /* Initialize video tee port */ … … 107 124 } 108 125 126 static 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 } 109 155 110 156 /* … … 123 169 if (tee->dst_port_cnt >= tee->dst_port_maxcnt) 124 170 return PJ_ETOOMANY; 125 171 126 172 if (vid_tee->info.fmt.id != port->info.fmt.id) 127 173 return PJMEDIA_EBADFMT; … … 131 177 vfd->size.h != vid_tee->info.fmt.det.vid.size.h) 132 178 { 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])); 136 186 tee->dst_ports[tee->dst_port_cnt].dst = port; 137 187 tee->dst_ports[tee->dst_port_cnt].option = option; 138 188 ++tee->dst_port_cnt; 139 189 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 */ 198 PJ_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 140 256 return PJ_SUCCESS; 141 257 } … … 158 274 pj_array_erase(tee->dst_ports, sizeof(tee->dst_ports[0]), 159 275 tee->dst_port_cnt, i); 276 pj_array_erase(tee->tee_conv, sizeof(tee->tee_conv[0]), 277 tee->dst_port_cnt, i); 160 278 --tee->dst_port_cnt; 161 279 return PJ_SUCCESS; … … 170 288 { 171 289 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)); 173 294 174 295 for (i = 0; i < tee->dst_port_cnt; ++i) { 175 296 pjmedia_frame frame_ = *frame; 176 297 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 } 189 353 } 190 354 … … 208 372 PJ_ASSERT_RETURN(port && port->info.signature==TEE_PORT_SIGN, PJ_EINVAL); 209 373 374 pj_pool_release(tee->pool); 375 if (tee->buf_pool) 376 pj_pool_release(tee->buf_pool); 377 210 378 pj_bzero(tee, sizeof(*tee)); 211 379
Note: See TracChangeset
for help on using the changeset viewer.