- Timestamp:
- Jul 12, 2011 10:03:02 AM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/vid_port.c
r3622 r3623 123 123 } 124 124 125 static pj_status_t create_converter(pjmedia_vid_port *vp) 126 { 127 /* Instantiate converter if necessary */ 128 if (vp->conv_param.src.id != vp->conv_param.dst.id || 129 vp->conv_param.src.det.vid.size.w != vp->conv_param.dst.det.vid.size.w || 130 vp->conv_param.src.det.vid.size.h != vp->conv_param.dst.det.vid.size.h) 131 { 132 pj_status_t status; 133 134 /* Yes, we need converter */ 135 const pjmedia_video_format_info *vfi; 136 pjmedia_video_apply_fmt_param vafp; 137 138 if (vp->conv) { 139 pjmedia_converter_destroy(vp->conv); 140 vp->conv = NULL; 141 } 142 143 status = pjmedia_converter_create(NULL, vp->pool, &vp->conv_param, 144 &vp->conv); 145 if (status != PJ_SUCCESS) { 146 PJ_PERROR(4,(THIS_FILE, status, "Error creating converter")); 147 return status; 148 } 149 150 /* Allocate buffer for conversion */ 151 vfi = pjmedia_get_video_format_info(NULL, vp->conv_param.dst.id); 152 if (!vfi) 153 return PJMEDIA_EBADFMT; 154 155 pj_bzero(&vafp, sizeof(vafp)); 156 vafp.size = vp->conv_param.dst.det.vid.size; 157 status = vfi->apply_fmt(vfi, &vafp); 158 if (status != PJ_SUCCESS) 159 return PJMEDIA_EBADFMT; 160 161 if (vafp.framebytes > vp->conv_buf_size) { 162 vp->conv_buf = pj_pool_alloc(vp->pool, vafp.framebytes); 163 vp->conv_buf_size = vafp.framebytes; 164 } 165 } 166 167 return PJ_SUCCESS; 168 } 169 125 170 PJ_DEF(pj_status_t) pjmedia_vid_port_create( pj_pool_t *pool, 126 171 const pjmedia_vid_port_param *prm, … … 153 198 /* Allocate videoport */ 154 199 vp = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_port); 155 vp->pool = p ool;200 vp->pool = pj_pool_create(pool->factory, "video port", 500, 500, NULL); 156 201 vp->role = prm->active ? ROLE_ACTIVE : ROLE_PASSIVE; 157 202 vp->dir = prm->vidparam.dir; … … 236 281 } 237 282 238 /* Instantiate converter if necessary */ 239 if (vparam.fmt.id != prm->vidparam.fmt.id || 240 vparam.fmt.det.vid.size.w != prm->vidparam.fmt.det.vid.size.w || 241 vparam.fmt.det.vid.size.h != prm->vidparam.fmt.det.vid.size.h /*|| 242 vparam.fmt.det.vid.fps.num != prm->vidparam.fmt.det.vid.fps.num || 243 vparam.fmt.det.vid.fps.denum != prm->vidparam.fmt.det.vid.fps.denum*/) 244 { 245 /* Yes, we need converter */ 246 const pjmedia_video_format_info *vfi; 247 pjmedia_video_apply_fmt_param vafp; 248 249 status = pjmedia_converter_create(NULL, pool, &vp->conv_param, 250 &vp->conv); 251 if (status != PJ_SUCCESS) { 252 PJ_PERROR(4,(THIS_FILE, status, "Error creating converter")); 253 goto on_error; 254 } 255 256 /* Allocate buffer for conversion */ 257 vfi = pjmedia_get_video_format_info(NULL, vp->conv_param.dst.id); 258 if (!vfi) 259 return PJMEDIA_EBADFMT; 260 261 pj_bzero(&vafp, sizeof(vafp)); 262 vafp.size = vp->conv_param.dst.det.vid.size; 263 status = vfi->apply_fmt(vfi, &vafp); 264 if (status != PJ_SUCCESS) 265 return PJMEDIA_EBADFMT; 266 267 vp->conv_buf = pj_pool_alloc(pool, vafp.framebytes); 268 vp->conv_buf_size = vafp.framebytes; 269 } 283 status = create_converter(vp); 284 if (status != PJ_SUCCESS) 285 goto on_error; 270 286 271 287 if (vp->role==ROLE_ACTIVE && vp->stream_role==ROLE_PASSIVE) { … … 489 505 PJ_LOG(4,(THIS_FILE, "Closing %s..", vp->dev_name.ptr)); 490 506 507 if (vp->conv) { 508 pjmedia_converter_destroy(vp->conv); 509 vp->conv = NULL; 510 } 491 511 if (vp->clock) { 492 512 pjmedia_clock_destroy(vp->clock); … … 506 526 vp->frm_mutex = NULL; 507 527 } 528 pj_pool_release(vp->pool); 508 529 } 509 530 … … 548 569 } 549 570 550 static pj_status_t convert_frame(pjmedia_vid_port *vp,551 pjmedia_frame *src_frame,552 pjmedia_frame *dst_frame)553 {554 pj_status_t status = PJ_SUCCESS;555 556 if (vp->conv) {557 dst_frame->buf = vp->conv_buf;558 dst_frame->size = vp->conv_buf_size;559 status = pjmedia_converter_convert(vp->conv,560 src_frame, dst_frame);561 }562 563 return status;564 }565 566 571 static pj_status_t client_port_event_cb(pjmedia_event_subscription *esub, 567 572 pjmedia_event *event) … … 572 577 const pjmedia_video_format_detail *vfd; 573 578 pj_status_t status; 574 579 575 580 ++event->proc_cnt; 576 581 577 582 pjmedia_vid_port_stop(vp); 578 583 579 584 /* Retrieve the video format detail */ 580 vfd = pjmedia_format_get_video_format_detail( 581 &vp->client_port->info.fmt,PJ_TRUE);585 vfd = pjmedia_format_get_video_format_detail(&vp->client_port->info.fmt, 586 PJ_TRUE); 582 587 if (!vfd) 583 588 return PJMEDIA_EVID_BADFORMAT; 584 589 pj_assert(vfd->fps.num); 585 586 if (vp->conv) { 587 /* Change the destination format to the new format */ 588 pjmedia_format_copy(&vp->conv_param.src, 589 &vp->client_port->info.fmt); 590 /* Only copy the size here */ 591 vp->conv_param.dst.det.vid.size = 592 vp->client_port->info.fmt.det.vid.size, 593 594 /* Recreate converter */ 595 pjmedia_converter_destroy(vp->conv); 596 status = pjmedia_converter_create(NULL, vp->pool, 597 &vp->conv_param, 598 &vp->conv); 599 if (status != PJ_SUCCESS) { 600 PJ_PERROR(4,(THIS_FILE, status, "Error recreating converter")); 601 return status; 602 } 603 } else { 604 vp->conv_param.dst = vp->client_port->info.fmt; 590 591 /* Change the destination format to the new format */ 592 pjmedia_format_copy(&vp->conv_param.src, 593 &vp->client_port->info.fmt); 594 /* Only copy the size here */ 595 vp->conv_param.dst.det.vid.size = 596 vp->client_port->info.fmt.det.vid.size, 597 598 status = create_converter(vp); 599 if (status != PJ_SUCCESS) { 600 PJ_PERROR(4,(THIS_FILE, status, "Error recreating converter")); 601 return status; 605 602 } 606 607 status = pjmedia_vid_dev_stream_set_cap( 608 vp->strm, 609 PJMEDIA_VID_DEV_CAP_FORMAT, 610 &vp->conv_param.dst); 603 604 status = pjmedia_vid_dev_stream_set_cap(vp->strm, 605 PJMEDIA_VID_DEV_CAP_FORMAT, 606 &vp->conv_param.dst); 611 607 if (status != PJ_SUCCESS) { 612 608 PJ_LOG(3, (THIS_FILE, "failure in changing the format of the " 613 609 "video device")); 614 610 PJ_LOG(3, (THIS_FILE, "reverting to its original format: %s", 615 616 611 status != PJMEDIA_EVID_ERR ? "success" : 612 "failure")); 617 613 return status; 618 614 } 619 615 620 616 if (vp->stream_role == ROLE_PASSIVE) { 621 617 pjmedia_vid_param vid_param; 622 618 pjmedia_clock_param clock_param; 623 619 624 620 /** 625 621 * Initially, frm_buf was allocated the biggest … … 633 629 pjmedia_clock_modify(vp->clock, &clock_param); 634 630 } 635 631 636 632 pjmedia_vid_port_start(vp); 637 633 } 638 634 639 635 /* Republish the event */ 640 636 return pjmedia_event_publish(&vp->epub, event); 637 } 638 639 static pj_status_t convert_frame(pjmedia_vid_port *vp, 640 pjmedia_frame *src_frame, 641 pjmedia_frame *dst_frame) 642 { 643 pj_status_t status = PJ_SUCCESS; 644 645 if (vp->conv) { 646 dst_frame->buf = vp->conv_buf; 647 dst_frame->size = vp->conv_buf_size; 648 status = pjmedia_converter_convert(vp->conv, 649 src_frame, dst_frame); 650 } 651 652 return status; 653 } 654 655 /* Copy frame to buffer. */ 656 static void copy_frame_to_buffer(pjmedia_vid_port *vp, 657 pjmedia_frame *frame) 658 { 659 pj_mutex_lock(vp->frm_mutex); 660 pjmedia_frame_copy(vp->frm_buf, frame); 661 pj_mutex_unlock(vp->frm_mutex); 662 } 663 664 /* Get frame from buffer and convert it if necessary. */ 665 static pj_status_t get_frame_from_buffer(pjmedia_vid_port *vp, 666 pjmedia_frame *frame) 667 { 668 pj_status_t status = PJ_SUCCESS; 669 670 pj_mutex_lock(vp->frm_mutex); 671 if (vp->conv) 672 status = convert_frame(vp, vp->frm_buf, frame); 673 else 674 pjmedia_frame_copy(frame, vp->frm_buf); 675 pj_mutex_unlock(vp->frm_mutex); 676 677 return status; 641 678 } 642 679 … … 647 684 */ 648 685 pjmedia_vid_port *vp = (pjmedia_vid_port*)user_data; 649 pjmedia_frame frame;650 686 pj_status_t status; 651 687 … … 664 700 //save_rgb_frame(vp->cap_size.w, vp->cap_size.h, vp->frm_buf); 665 701 666 if (convert_frame(vp, vp->frm_buf, &frame) != PJ_SUCCESS) 667 return; 668 669 status = pjmedia_port_put_frame(vp->client_port, 670 (vp->conv? &frame: vp->frm_buf)); 702 vidstream_cap_cb(vp->strm, vp, vp->frm_buf); 671 703 } 672 704 … … 679 711 pj_status_t status; 680 712 pjmedia_frame frame; 681 unsigned frame_ts = vp->clocksrc.clock_rate / 1000 *682 vp->clocksrc.ptime_usec / 1000;683 713 684 714 pj_assert(vp->role==ROLE_ACTIVE && vp->stream_role==ROLE_PASSIVE); … … 689 719 return; 690 720 691 if (vp->sync_clocksrc.sync_clocksrc) { 692 pjmedia_clock_src *src = vp->sync_clocksrc.sync_clocksrc; 693 pj_int32_t diff; 694 unsigned nsync_frame; 695 696 /* Synchronization */ 697 /* Calculate the time difference (in ms) with the sync source */ 698 diff = pjmedia_clock_src_get_time_msec(&vp->clocksrc) - 699 pjmedia_clock_src_get_time_msec(src) - 700 vp->sync_clocksrc.sync_delta; 701 702 /* Check whether sync source made a large jump */ 703 if (diff < 0 && -diff > PJMEDIA_CLOCK_SYNC_MAX_SYNC_MSEC) { 704 pjmedia_clock_src_update(&vp->clocksrc, NULL); 705 vp->sync_clocksrc.sync_delta = 706 pjmedia_clock_src_get_time_msec(src) - 707 pjmedia_clock_src_get_time_msec(&vp->clocksrc); 708 vp->sync_clocksrc.nsync_frame = 0; 709 return; 710 } 711 712 /* Calculate the difference (in frames) with the sync source */ 713 nsync_frame = abs(diff) * 1000 / vp->clocksrc.ptime_usec; 714 if (nsync_frame == 0) { 715 /* Nothing to sync */ 716 vp->sync_clocksrc.nsync_frame = 0; 717 } else { 718 pj_int32_t init_sync_frame = nsync_frame; 719 720 /* Check whether it's a new sync or whether we need to reset 721 * the sync 722 */ 723 if (vp->sync_clocksrc.nsync_frame == 0 || 724 (vp->sync_clocksrc.nsync_frame > 0 && 725 nsync_frame > vp->sync_clocksrc.nsync_frame)) 726 { 727 vp->sync_clocksrc.nsync_frame = nsync_frame; 728 vp->sync_clocksrc.nsync_progress = 0; 729 } else { 730 init_sync_frame = vp->sync_clocksrc.nsync_frame; 731 } 732 733 if (diff >= 0) { 734 unsigned skip_mod; 735 736 /* We are too fast */ 737 if (vp->sync_clocksrc.max_sync_ticks > 0) { 738 skip_mod = init_sync_frame / 739 vp->sync_clocksrc.max_sync_ticks + 2; 740 } else 741 skip_mod = init_sync_frame + 2; 742 743 PJ_LOG(5, (THIS_FILE, "synchronization: early by %d ms", 744 diff)); 745 /* We'll play a frame every skip_mod-th tick instead of 746 * a complete pause 747 */ 748 if (++vp->sync_clocksrc.nsync_progress % skip_mod > 0) { 749 pjmedia_clock_src_update(&vp->clocksrc, NULL); 750 return; 751 } 752 } else { 753 unsigned i, ndrop = init_sync_frame; 754 755 /* We are too late, drop the frame */ 756 if (vp->sync_clocksrc.max_sync_ticks > 0) { 757 ndrop /= vp->sync_clocksrc.max_sync_ticks; 758 ndrop++; 759 } 760 PJ_LOG(5, (THIS_FILE, "synchronization: late, " 761 "dropping %d frame(s)", ndrop)); 762 763 if (ndrop >= nsync_frame) { 764 vp->sync_clocksrc.nsync_frame = 0; 765 ndrop = nsync_frame; 766 } else 767 vp->sync_clocksrc.nsync_progress += ndrop; 768 769 for (i = 0; i < ndrop; i++) { 770 vp->frm_buf->size = vp->frm_buf_size; 771 status = pjmedia_port_get_frame(vp->client_port, 772 vp->frm_buf); 773 if (status != PJ_SUCCESS) { 774 pjmedia_clock_src_update(&vp->clocksrc, NULL); 775 return; 776 } 777 778 pj_add_timestamp32(&vp->clocksrc.timestamp, 779 frame_ts); 780 } 781 } 782 } 783 } 784 785 vp->frm_buf->size = vp->frm_buf_size; 786 status = pjmedia_port_get_frame(vp->client_port, vp->frm_buf); 787 if (status != PJ_SUCCESS) { 788 pjmedia_clock_src_update(&vp->clocksrc, NULL); 789 return; 790 } 791 pj_add_timestamp32(&vp->clocksrc.timestamp, frame_ts); 792 pjmedia_clock_src_update(&vp->clocksrc, NULL); 793 794 if (convert_frame(vp, vp->frm_buf, &frame) != PJ_SUCCESS) 721 status = vidstream_render_cb(vp->strm, vp, &frame); 722 if (status != PJ_SUCCESS) 795 723 return; 796 797 status = pjmedia_vid_dev_stream_put_frame(vp->strm, 798 (vp->conv? &frame: vp->frm_buf)); 724 725 status = pjmedia_vid_dev_stream_put_frame(vp->strm, &frame); 799 726 } 800 727 … … 814 741 815 742 if (vp->client_port) 816 returnpjmedia_port_put_frame(vp->client_port,743 status = pjmedia_port_put_frame(vp->client_port, 817 744 (vp->conv? &frame_: frame)); 745 if (status != PJ_SUCCESS) 746 return status; 818 747 } else { 819 pj_mutex_lock(vp->frm_mutex); 820 pjmedia_frame_copy(vp->frm_buf, frame); 821 pj_mutex_unlock(vp->frm_mutex); 822 } 823 /* 748 /* We are passive while the stream is active so we just store the 749 * frame in the buffer. 750 * The decoding counterpart is located in vid_pasv_port_put_frame() 751 */ 752 copy_frame_to_buffer(vp, frame); 753 } 754 /* This is tricky since the frame is still in its original unconverted 755 * format, which may not be what the application expects. 756 */ 824 757 if (vp->strm_cb.capture_cb) 825 758 return (*vp->strm_cb.capture_cb)(stream, vp->strm_cb_data, frame); 826 */827 759 return PJ_SUCCESS; 828 760 } … … 836 768 837 769 if (vp->role==ROLE_ACTIVE) { 838 if (vp->client_port) { 839 return pjmedia_port_get_frame(vp->client_port, frame); 770 unsigned frame_ts = vp->clocksrc.clock_rate / 1000 * 771 vp->clocksrc.ptime_usec / 1000; 772 773 if (!vp->client_port) 774 return status; 775 776 if (vp->sync_clocksrc.sync_clocksrc) { 777 pjmedia_clock_src *src = vp->sync_clocksrc.sync_clocksrc; 778 pj_int32_t diff; 779 unsigned nsync_frame; 780 781 /* Synchronization */ 782 /* Calculate the time difference (in ms) with the sync source */ 783 diff = pjmedia_clock_src_get_time_msec(&vp->clocksrc) - 784 pjmedia_clock_src_get_time_msec(src) - 785 vp->sync_clocksrc.sync_delta; 786 787 /* Check whether sync source made a large jump */ 788 if (diff < 0 && -diff > PJMEDIA_CLOCK_SYNC_MAX_SYNC_MSEC) { 789 pjmedia_clock_src_update(&vp->clocksrc, NULL); 790 vp->sync_clocksrc.sync_delta = 791 pjmedia_clock_src_get_time_msec(src) - 792 pjmedia_clock_src_get_time_msec(&vp->clocksrc); 793 vp->sync_clocksrc.nsync_frame = 0; 794 return status; 795 } 796 797 /* Calculate the difference (in frames) with the sync source */ 798 nsync_frame = abs(diff) * 1000 / vp->clocksrc.ptime_usec; 799 if (nsync_frame == 0) { 800 /* Nothing to sync */ 801 vp->sync_clocksrc.nsync_frame = 0; 802 } else { 803 pj_int32_t init_sync_frame = nsync_frame; 804 805 /* Check whether it's a new sync or whether we need to reset 806 * the sync 807 */ 808 if (vp->sync_clocksrc.nsync_frame == 0 || 809 (vp->sync_clocksrc.nsync_frame > 0 && 810 nsync_frame > vp->sync_clocksrc.nsync_frame)) 811 { 812 vp->sync_clocksrc.nsync_frame = nsync_frame; 813 vp->sync_clocksrc.nsync_progress = 0; 814 } else { 815 init_sync_frame = vp->sync_clocksrc.nsync_frame; 816 } 817 818 if (diff >= 0) { 819 unsigned skip_mod; 820 821 /* We are too fast */ 822 if (vp->sync_clocksrc.max_sync_ticks > 0) { 823 skip_mod = init_sync_frame / 824 vp->sync_clocksrc.max_sync_ticks + 2; 825 } else 826 skip_mod = init_sync_frame + 2; 827 828 PJ_LOG(5, (THIS_FILE, "synchronization: early by %d ms", 829 diff)); 830 /* We'll play a frame every skip_mod-th tick instead of 831 * a complete pause 832 */ 833 if (++vp->sync_clocksrc.nsync_progress % skip_mod > 0) { 834 pjmedia_clock_src_update(&vp->clocksrc, NULL); 835 return status; 836 } 837 } else { 838 unsigned i, ndrop = init_sync_frame; 839 840 /* We are too late, drop the frame */ 841 if (vp->sync_clocksrc.max_sync_ticks > 0) { 842 ndrop /= vp->sync_clocksrc.max_sync_ticks; 843 ndrop++; 844 } 845 PJ_LOG(5, (THIS_FILE, "synchronization: late, " 846 "dropping %d frame(s)", ndrop)); 847 848 if (ndrop >= nsync_frame) { 849 vp->sync_clocksrc.nsync_frame = 0; 850 ndrop = nsync_frame; 851 } else 852 vp->sync_clocksrc.nsync_progress += ndrop; 853 854 for (i = 0; i < ndrop; i++) { 855 vp->frm_buf->size = vp->frm_buf_size; 856 status = pjmedia_port_get_frame(vp->client_port, 857 vp->frm_buf); 858 if (status != PJ_SUCCESS) { 859 pjmedia_clock_src_update(&vp->clocksrc, NULL); 860 return status; 861 } 862 863 pj_add_timestamp32(&vp->clocksrc.timestamp, 864 frame_ts); 865 } 866 } 867 } 840 868 } 869 870 vp->frm_buf->size = vp->frm_buf_size; 871 status = pjmedia_port_get_frame(vp->client_port, vp->frm_buf); 872 if (status != PJ_SUCCESS) { 873 pjmedia_clock_src_update(&vp->clocksrc, NULL); 874 return status; 875 } 876 pj_add_timestamp32(&vp->clocksrc.timestamp, frame_ts); 877 pjmedia_clock_src_update(&vp->clocksrc, NULL); 878 879 frame = vp->frm_buf; 880 if (convert_frame(vp, vp->frm_buf, frame) != PJ_SUCCESS) 881 return status; 841 882 } else { 842 pj_mutex_lock(vp->frm_mutex); 843 if (vp->conv) 844 status = convert_frame(vp, vp->frm_buf, frame); 845 else 846 pjmedia_frame_copy(frame, vp->frm_buf); 847 pj_mutex_unlock(vp->frm_mutex); 883 /* The stream is active while we are passive so we need to get the 884 * frame from the buffer. 885 * The encoding counterpart is located in vid_pasv_port_get_frame() 886 */ 887 get_frame_from_buffer(vp, frame); 848 888 } 849 889 if (vp->strm_cb.render_cb) … … 859 899 860 900 if (vp->stream_role==ROLE_PASSIVE) { 901 /* We are passive and the stream is passive. 902 * The encoding counterpart is in vid_pasv_port_get_frame(). 903 */ 861 904 pj_status_t status; 862 905 pjmedia_frame frame_; … … 869 912 (vp->conv? &frame_: frame)); 870 913 } else { 871 pj_mutex_lock(vp->frm_mutex); 872 pjmedia_frame_copy(vp->frm_buf, frame); 873 pj_mutex_unlock(vp->frm_mutex); 914 /* We are passive while the stream is active so we just store the 915 * frame in the buffer. 916 * The encoding counterpart is located in vidstream_cap_cb() 917 */ 918 copy_frame_to_buffer(vp, frame); 874 919 } 875 920 … … 885 930 886 931 if (vp->stream_role==ROLE_PASSIVE) { 932 /* We are passive and the stream is passive. 933 * The decoding counterpart is in vid_pasv_port_put_frame(). 934 */ 887 935 status = pjmedia_vid_dev_stream_get_frame(vp->strm, 888 936 (vp->conv? vp->frm_buf: … … 893 941 status = convert_frame(vp, vp->frm_buf, frame); 894 942 } else { 895 pj_mutex_lock(vp->frm_mutex); 896 if (vp->conv) 897 status = convert_frame(vp, vp->frm_buf, frame); 898 else 899 pjmedia_frame_copy(frame, vp->frm_buf); 900 pj_mutex_unlock(vp->frm_mutex); 943 /* The stream is active while we are passive so we need to get the 944 * frame from the buffer. 945 * The decoding counterpart is located in vidstream_rend_cb() 946 */ 947 get_frame_from_buffer(vp, frame); 901 948 } 902 949
Note: See TracChangeset
for help on using the changeset viewer.