Changeset 5026 for pjproject/trunk
- Timestamp:
- Mar 26, 2015 4:14:20 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/vid_port.c
r5012 r5026 26 26 #include <pj/pool.h> 27 27 28 29 28 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) 30 29 … … 32 31 #define SIGNATURE PJMEDIA_SIG_VID_PORT 33 32 #define THIS_FILE "vid_port.c" 33 34 35 /** 36 * Enable this to trace the format matching process. 37 */ 38 #if 0 39 # define TRACE_FIND_FMT(args) PJ_LOG(5,args) 40 #else 41 # define TRACE_FIND_FMT(args) 42 #endif 43 44 /** 45 * We use nearest width and aspect ratio to find match between the requested 46 * format and the supported format. Specify this to determine the array size 47 * of the supported formats with the nearest width. From this array, we will 48 * find the one with lowest diff_ratio. Setting this to 1 will thus skip 49 * the aspect ratio calculation. 50 */ 51 #ifndef PJMEDIA_VID_PORT_MATCH_WIDTH_ARRAY_SIZE 52 # define PJMEDIA_VID_PORT_MATCH_WIDTH_ARRAY_SIZE 3 53 #endif 34 54 35 55 typedef struct vid_pasv_port vid_pasv_port; … … 40 60 ROLE_ACTIVE, 41 61 ROLE_PASSIVE 62 }; 63 64 enum fmt_match 65 { 66 FMT_MATCH, 67 FMT_SAME_COLOR_SPACE, 68 FMT_DIFF_COLOR_SPACE 42 69 }; 43 70 … … 89 116 }; 90 117 118 struct fmt_prop 119 { 120 pj_uint32_t id; 121 pjmedia_rect_size size; 122 pjmedia_ratio fps; 123 }; 124 91 125 static pj_status_t vidstream_cap_cb(pjmedia_vid_dev_stream *stream, 92 126 void *user_data, … … 182 216 183 217 return PJ_SUCCESS; 218 } 219 220 static pj_uint32_t match_format_id(pj_uint32_t req_id, 221 pj_uint32_t sup_id) 222 { 223 const pjmedia_video_format_info *req_fmt_info, *sup_fmt_info; 224 225 if (req_id == sup_id) 226 return FMT_MATCH; 227 228 req_fmt_info = pjmedia_get_video_format_info( 229 pjmedia_video_format_mgr_instance(), 230 req_id); 231 232 sup_fmt_info = pjmedia_get_video_format_info( 233 pjmedia_video_format_mgr_instance(), 234 sup_id); 235 236 if (req_fmt_info->color_model == sup_fmt_info->color_model) { 237 return FMT_SAME_COLOR_SPACE; 238 } 239 240 return FMT_DIFF_COLOR_SPACE; 241 } 242 243 static pj_uint32_t get_match_format_id(pj_uint32_t req_fmt_id, 244 pjmedia_vid_dev_info *di) 245 { 246 unsigned i = 0, match_idx = 0, match_fmt = FMT_DIFF_COLOR_SPACE+1; 247 248 /* Find the matching format. If no exact match is found, find 249 * the supported format with the same color space. If no match is found, 250 * use the first supported format on the list. 251 */ 252 for (i; i < di->fmt_cnt; ++i) { 253 unsigned tmp_fmt = match_format_id(req_fmt_id, di->fmt[i].id); 254 255 if (match_fmt == FMT_MATCH) 256 return req_fmt_id; 257 258 if (tmp_fmt < match_fmt) { 259 match_idx = i; 260 match_fmt = tmp_fmt; 261 } 262 } 263 return di->fmt[match_idx].id; 264 } 265 266 /** 267 * Find the closest supported format from the specific requested format. 268 * The algo is to find a supported size with the matching format id, width and 269 * lowest diff_ratio. 270 * --- 271 * For format id matching, the priority is: 272 * 1. Find exact match 273 * 2. Find format with the same color space 274 * 3. Use the first supported format. 275 * --- 276 * For ratio matching: 277 * Find the lowest difference of the aspect ratio between the requested and 278 * the supported format. 279 */ 280 static struct fmt_prop find_closest_fmt(pj_uint32_t req_fmt_id, 281 pjmedia_rect_size *req_fmt_size, 282 pjmedia_ratio *req_fmt_fps, 283 pjmedia_vid_dev_info *di) 284 { 285 unsigned i, match_idx = 0; 286 pj_uint32_t match_fmt_id; 287 float req_ratio, min_diff_ratio = 0.0; 288 struct fmt_prop ret_prop; 289 pj_bool_t found_exact_match = PJ_FALSE; 290 291 #define GET_DIFF(x, y) ((x) > (y)? (x-y) : (y-x)) 292 293 /* This will contain the supported format with lowest width difference */ 294 pjmedia_rect_size nearest_width[PJMEDIA_VID_PORT_MATCH_WIDTH_ARRAY_SIZE]; 295 296 /* Initialize the list. */ 297 for (i=0;i<PJMEDIA_VID_PORT_MATCH_WIDTH_ARRAY_SIZE;++i) { 298 nearest_width[i].w = 0xFFFFFFFF; 299 nearest_width[i].h = 0; 300 } 301 302 /* Get the matching format id. We assume each format will support all 303 * image size. 304 */ 305 match_fmt_id = get_match_format_id(req_fmt_id, di); 306 307 /* Search from the supported format, the smallest diff width. Stop the 308 * search if exact match is found. 309 */ 310 for (i=0;i<di->fmt_cnt;++i) { 311 pjmedia_video_format_detail *vfd; 312 unsigned diff_width1, diff_width2; 313 314 /* Ignore supported format with different format id. */ 315 if (di->fmt[i].id != match_fmt_id) 316 continue; 317 318 vfd = pjmedia_format_get_video_format_detail(&di->fmt[i], PJ_TRUE); 319 320 /* Exact match found. */ 321 if ((vfd->size.w == req_fmt_size->w) && 322 (vfd->size.h == req_fmt_size->h)) 323 { 324 nearest_width[0] = vfd->size; 325 found_exact_match = PJ_TRUE; 326 break; 327 } 328 329 diff_width1 = GET_DIFF(vfd->size.w, req_fmt_size->w); 330 diff_width2 = GET_DIFF(nearest_width[0].w, req_fmt_size->w); 331 332 /* Fill the nearest width list. */ 333 if (diff_width1 <= diff_width2) { 334 int k = 1; 335 pjmedia_rect_size tmp_size = vfd->size; 336 337 while(((GET_DIFF(tmp_size.w, req_fmt_size->w) < 338 (GET_DIFF(nearest_width[k].w, req_fmt_size->w))) && 339 (k < PJ_ARRAY_SIZE(nearest_width)))) 340 { 341 nearest_width[k-1] = nearest_width[k]; 342 ++k; 343 } 344 nearest_width[k-1] = tmp_size; 345 } 346 } 347 /* No need to calculate ratio if exact match is found. */ 348 if (!found_exact_match) { 349 /* We have the list of supported format with nearest width. Now get the 350 * best ratio. 351 */ 352 req_ratio = (float)req_fmt_size->w / (float)req_fmt_size->h; 353 for (i=0;i<PJ_ARRAY_SIZE(nearest_width);++i) { 354 float sup_ratio, diff_ratio; 355 356 if (nearest_width[i].w == 0xFFFFFFFF) 357 continue; 358 359 sup_ratio = (float)nearest_width[i].w / (float)nearest_width[i].h; 360 361 diff_ratio = GET_DIFF(sup_ratio, req_ratio); 362 363 if ((i==0) || (diff_ratio <= min_diff_ratio)) { 364 match_idx = i; 365 min_diff_ratio = diff_ratio; 366 } 367 } 368 } 369 ret_prop.id = match_fmt_id; 370 ret_prop.size = nearest_width[match_idx]; 371 ret_prop.fps = *req_fmt_fps; 372 return ret_prop; 373 } 374 375 /** 376 * This is to test the algo to find the closest fmt 377 */ 378 static void test_find_closest_fmt(pjmedia_vid_dev_info *di) 379 { 380 unsigned i, j, k; 381 char fmt_name[5]; 382 383 pjmedia_rect_size find_size[] = { 384 {720, 480}, 385 {352, 288}, 386 {400, 300}, 387 {1600, 900}, 388 {255, 352}, 389 {500, 500}, 390 }; 391 392 pjmedia_ratio find_fps[] = { 393 {1, 1}, 394 {10, 1}, 395 {15, 1}, 396 {30, 1}, 397 }; 398 399 pj_uint32_t find_id[] = { 400 PJMEDIA_FORMAT_RGB24, 401 PJMEDIA_FORMAT_RGBA, 402 PJMEDIA_FORMAT_AYUV, 403 PJMEDIA_FORMAT_YUY2, 404 PJMEDIA_FORMAT_I420 405 }; 406 407 TRACE_FIND_FMT((THIS_FILE, "Supported format = ")); 408 for (i = 0; i < di->fmt_cnt; i++) { 409 //pjmedia_video_format_detail *vid_fd = 410 // pjmedia_format_get_video_format_detail(&di->fmt[i], PJ_TRUE); 411 412 pjmedia_fourcc_name(di->fmt[i].id, fmt_name); 413 414 TRACE_FIND_FMT((THIS_FILE, "id:%s size:%d*%d fps:%d/%d", 415 fmt_name, 416 vid_fd->size.w, 417 vid_fd->size.h, 418 vid_fd->fps.num, 419 vid_fd->fps.denum)); 420 } 421 422 for (i = 0; i < PJ_ARRAY_SIZE(find_id); i++) { 423 424 for (j = 0; j < PJ_ARRAY_SIZE(find_fps); j++) { 425 426 for (k = 0; k < PJ_ARRAY_SIZE(find_size); k++) { 427 struct fmt_prop match_prop; 428 429 pjmedia_fourcc_name(find_id[i], fmt_name); 430 431 TRACE_FIND_FMT((THIS_FILE, "Trying to find closest match " 432 "id:%s size:%dx%d fps:%d/%d", 433 fmt_name, 434 find_size[k].w, 435 find_size[k].h, 436 find_fps[j].num, 437 find_fps[j].denum)); 438 439 match_prop = find_closest_fmt(find_id[i], 440 &find_size[k], 441 &find_fps[j], 442 di); 443 444 if ((match_prop.id == find_id[i]) && 445 (match_prop.size.w == find_size[k].w) && 446 (match_prop.size.h == find_size[k].h) && 447 (match_prop.fps.num / match_prop.fps.denum == 448 find_fps[j].num * find_fps[j].denum)) 449 { 450 TRACE_FIND_FMT((THIS_FILE, "Exact Match found!!")); 451 } else { 452 pjmedia_fourcc_name(match_prop.id, fmt_name); 453 TRACE_FIND_FMT((THIS_FILE, "Closest format = "\ 454 "id:%s size:%dx%d fps:%d/%d", 455 fmt_name, 456 match_prop.size.w, 457 match_prop.size.h, 458 match_prop.fps.num, 459 match_prop.fps.denum)); 460 } 461 } 462 } 463 } 184 464 } 185 465 … … 189 469 { 190 470 pjmedia_vid_port *vp; 191 constpjmedia_video_format_detail *vfd;471 pjmedia_video_format_detail *vfd; 192 472 char dev_name[64]; 193 473 char fmt_name[5]; … … 198 478 pjmedia_vid_dev_param vparam; 199 479 pjmedia_vid_dev_info di; 200 unsigned i;201 480 202 481 PJ_ASSERT_RETURN(pool && prm && p_vid_port, PJ_EINVAL); … … 234 513 di.name, di.driver); 235 514 236 for (i = 0; i < di.fmt_cnt; ++i) { 237 if (prm->vidparam.fmt.id == di.fmt[i].id) 238 break; 239 } 240 241 if (i == di.fmt_cnt) { 242 /* The device has no no matching format. Pick one from 243 * the supported formats, and later use converter to 244 * convert it to the required format. 245 */ 246 pj_assert(di.fmt_cnt != 0); 247 vparam.fmt.id = di.fmt[0].id; 515 if (di.dir == PJMEDIA_DIR_RENDER) { 516 /* Find the matching format. If no exact match is found, find 517 * the supported format with the same color space. If no match is found, 518 * use the first supported format on the list. 519 */ 520 pj_assert(di.fmt_cnt != 0); 521 vparam.fmt.id = get_match_format_id(prm->vidparam.fmt.id, &di); 522 } else { 523 struct fmt_prop match_prop; 524 525 if (di.fmt_cnt == 0) { 526 status = PJMEDIA_EVID_SYSERR; 527 PJ_PERROR(4,(THIS_FILE, status, "Device has no supported format")); 528 return status; 529 } 530 531 #if 0 532 test_find_closest_fmt(&di); 533 #endif 534 535 pjmedia_fourcc_name(vparam.fmt.id, fmt_name); 536 PJ_LOG(4,(THIS_FILE, 537 "Finding best match for %s(%s) format=%s, size=%dx%d "\ 538 "@%d:%d fps", 539 dev_name, vid_dir_name(prm->vidparam.dir), fmt_name, 540 vfd->size.w, vfd->size.h, vfd->fps.num, vfd->fps.denum)); 541 542 match_prop = find_closest_fmt(prm->vidparam.fmt.id, 543 &vfd->size, 544 &vfd->fps, 545 &di); 546 547 if ((match_prop.id != prm->vidparam.fmt.id) || 548 (match_prop.size.w != vfd->size.w) || 549 (match_prop.size.h != vfd->size.h)) 550 { 551 vparam.fmt.id = match_prop.id; 552 vparam.fmt.det.vid.size = match_prop.size; 553 vfd->size = match_prop.size; 554 } 248 555 } 249 556
Note: See TracChangeset
for help on using the changeset viewer.