Changeset 3776 for pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c
- Timestamp:
- Sep 29, 2011 8:31:15 AM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c
r3667 r3776 124 124 unsigned frame_ts_len; /**< Frame length in timestamp. */ 125 125 126 unsigned rx_frame_cnt; /**< # of array in rx_frames */ 127 pjmedia_frame *rx_frames; /**< Temp. buffer for incoming 128 frame assembly. */ 129 126 130 #if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0 127 131 pj_bool_t use_ka; /**< Stream keep-alive with non- … … 732 736 void *rtphdr; 733 737 int rtphdrlen; 734 unsigned processed = 0; 738 pj_bool_t has_more_data = PJ_FALSE; 739 pj_size_t total_sent = 0; 735 740 736 741 … … 767 772 768 773 /* Encode! */ 769 status = pjmedia_vid_codec_encode(stream->codec, frame, 770 channel->buf_size - 771 sizeof(pjmedia_rtp_hdr), 772 &frame_out); 774 status = pjmedia_vid_codec_encode_begin(stream->codec, frame, 775 channel->buf_size - 776 sizeof(pjmedia_rtp_hdr), 777 &frame_out, 778 &has_more_data); 773 779 if (status != PJ_SUCCESS) { 774 LOGERR_((channel->port.info.name.ptr, 775 "Codec encode() error", status));780 LOGERR_((channel->port.info.name.ptr, 781 "Codec encode_begin() error", status)); 776 782 777 783 /* Update RTP timestamp */ 778 784 pjmedia_rtp_encode_rtp(&channel->rtp, channel->pt, 1, 0, 779 rtp_ts_len, (const void**)&rtphdr, &rtphdrlen); 780 return status; 781 } 782 783 784 while (processed < frame_out.size) { 785 pj_uint8_t *payload; 786 pj_uint8_t *rtp_pkt; 787 pj_size_t payload_len; 788 789 /* Generate RTP payload */ 790 status = pjmedia_vid_codec_packetize(stream->codec, 791 (pj_uint8_t*)frame_out.buf, 792 frame_out.size, 793 &processed, 794 (const pj_uint8_t**)&payload, 795 &payload_len); 796 if (status != PJ_SUCCESS) { 797 LOGERR_((channel->port.info.name.ptr, 798 "Codec pack() error", status)); 799 800 /* Update RTP timestamp */ 801 pjmedia_rtp_encode_rtp(&channel->rtp, channel->pt, 1, 0, 802 rtp_ts_len, (const void**)&rtphdr, 803 &rtphdrlen); 804 return status; 805 } 806 807 /* Encapsulate. */ 808 status = pjmedia_rtp_encode_rtp( &channel->rtp, 809 channel->pt, 810 (processed==frame_out.size?1:0), 811 payload_len, 812 rtp_ts_len, 813 (const void**)&rtphdr, 814 &rtphdrlen); 815 816 if (status != PJ_SUCCESS) { 817 LOGERR_((channel->port.info.name.ptr, 785 rtp_ts_len, (const void**)&rtphdr, 786 &rtphdrlen); 787 return status; 788 } 789 790 /* Loop while we have frame to send */ 791 for (;;) { 792 status = pjmedia_rtp_encode_rtp(&channel->rtp, 793 channel->pt, 794 (has_more_data == PJ_FALSE ? 1 : 0), 795 frame_out.size, 796 rtp_ts_len, 797 (const void**)&rtphdr, 798 &rtphdrlen); 799 if (status != PJ_SUCCESS) { 800 LOGERR_((channel->port.info.name.ptr, 818 801 "RTP encode_rtp() error", status)); 819 802 return status; 820 } 821 822 /* Next packets use same timestamp */ 823 rtp_ts_len = 0; 824 825 rtp_pkt = payload - sizeof(pjmedia_rtp_hdr); 826 827 /* Copy RTP header to the beginning of packet */ 828 pj_memcpy(rtp_pkt, rtphdr, sizeof(pjmedia_rtp_hdr)); 829 830 /* Send the RTP packet to the transport. */ 831 pjmedia_transport_send_rtp(stream->transport, rtp_pkt, 832 payload_len + sizeof(pjmedia_rtp_hdr)); 803 } 804 805 // Copy RTP header to the beginning of packet 806 pj_memcpy(channel->buf, rtphdr, sizeof(pjmedia_rtp_hdr)); 807 808 // Send the RTP packet to the transport. 809 status = pjmedia_transport_send_rtp(stream->transport, 810 (char*)channel->buf, 811 frame_out.size + 812 sizeof(pjmedia_rtp_hdr)); 813 if (status != PJ_SUCCESS) { 814 LOGERR_((channel->port.info.name.ptr, 815 "Transport send_rtp() error", status)); 816 /* Ignore this error */ 817 } 818 819 total_sent += frame_out.size; 820 821 if (!has_more_data) 822 break; 823 824 /* Next packets use same timestamp */ 825 rtp_ts_len = 0; 826 827 frame_out.size = 0; 828 829 /* Encode more! */ 830 status = pjmedia_vid_codec_encode_more(stream->codec, 831 channel->buf_size - 832 sizeof(pjmedia_rtp_hdr), 833 &frame_out, 834 &has_more_data); 835 if (status != PJ_SUCCESS) { 836 LOGERR_((channel->port.info.name.ptr, 837 "Codec encode_more() error", status)); 838 /* Ignore this error (?) */ 839 break; 840 } 833 841 } 834 842 … … 842 850 843 851 /* Do nothing if we have nothing to transmit */ 844 if ( frame_out.size== 0) {852 if (total_sent == 0) { 845 853 return PJ_SUCCESS; 846 854 } 847 855 848 856 /* Update stat */ 849 pjmedia_rtcp_tx_rtp(&stream->rtcp, frame_out.size);857 pjmedia_rtcp_tx_rtp(&stream->rtcp, total_sent); 850 858 stream->rtcp.stat.rtp_tx_last_ts = pj_ntohl(stream->enc->rtp.out_hdr.ts); 851 859 stream->rtcp.stat.rtp_tx_last_seq = pj_ntohs(stream->enc->rtp.out_hdr.seq); … … 864 872 pjmedia_vid_stream *stream = (pjmedia_vid_stream*) port->port_data.pdata; 865 873 pjmedia_vid_channel *channel = stream->dec; 866 pjmedia_frame frame_in;867 874 pj_uint32_t last_ts = 0; 868 875 int frm_first_seq = 0, frm_last_seq = 0; 876 pj_bool_t got_frame = PJ_FALSE; 877 unsigned cnt; 869 878 pj_status_t status; 870 879 … … 876 885 877 886 /* Repeat get payload from the jitter buffer until all payloads with same 878 * timestamp are collected (a complete frame unpacketized).887 * timestamp are collected. 879 888 */ 880 { 881 pj_bool_t got_frame; 882 unsigned cnt; 883 884 channel->buf_len = 0; 885 got_frame = PJ_FALSE; 886 887 /* Lock jitter buffer mutex first */ 888 pj_mutex_lock( stream->jb_mutex ); 889 890 /* Check if we got a decodable frame */ 891 for (cnt=0; ; ++cnt) { 892 char ptype; 893 pj_uint32_t ts; 894 int seq; 895 896 /* Peek frame from jitter buffer. */ 897 pjmedia_jbuf_peek_frame(stream->jb, cnt, NULL, NULL, 898 &ptype, NULL, &ts, &seq); 899 if (ptype == PJMEDIA_JB_NORMAL_FRAME) { 900 if (last_ts == 0) { 901 last_ts = ts; 902 frm_first_seq = seq; 903 } 904 if (ts != last_ts) { 905 got_frame = PJ_TRUE; 906 break; 907 } 908 frm_last_seq = seq; 909 } else if (ptype == PJMEDIA_JB_ZERO_EMPTY_FRAME) { 910 /* No more packet in the jitter buffer */ 889 channel->buf_len = 0; 890 891 /* Lock jitter buffer mutex first */ 892 pj_mutex_lock( stream->jb_mutex ); 893 894 /* Check if we got a decodable frame */ 895 for (cnt=0; ; ++cnt) { 896 char ptype; 897 pj_uint32_t ts; 898 int seq; 899 900 /* Peek frame from jitter buffer. */ 901 pjmedia_jbuf_peek_frame(stream->jb, cnt, NULL, NULL, 902 &ptype, NULL, &ts, &seq); 903 if (ptype == PJMEDIA_JB_NORMAL_FRAME) { 904 if (last_ts == 0) { 905 last_ts = ts; 906 frm_first_seq = seq; 907 } 908 if (ts != last_ts) { 909 got_frame = PJ_TRUE; 911 910 break; 912 911 } 912 frm_last_seq = seq; 913 } else if (ptype == PJMEDIA_JB_ZERO_EMPTY_FRAME) { 914 /* No more packet in the jitter buffer */ 915 break; 913 916 } 914 915 if (got_frame) { 916 unsigned i; 917 918 /* Generate frame bitstream from the payload */ 919 channel->buf_len = 0; 920 for (i = 0; i < cnt; ++i) { 921 const pj_uint8_t *p; 922 pj_size_t psize; 923 char ptype; 924 925 /* We use jbuf_peek_frame() as it will returns the pointer of 926 * the payload (no buffer and memcpy needed), just as we need. 927 */ 928 pjmedia_jbuf_peek_frame(stream->jb, i, (const void**)&p, 929 &psize, &ptype, NULL, NULL, NULL); 930 931 if (ptype != PJMEDIA_JB_NORMAL_FRAME) { 932 /* Packet lost, must set payload to NULL and keep going */ 933 p = NULL; 934 psize = 0; 935 } 936 937 status = pjmedia_vid_codec_unpacketize( 938 stream->codec, 939 p, psize, 940 (pj_uint8_t*)channel->buf, 941 channel->buf_size, 942 &channel->buf_len); 943 if (status != PJ_SUCCESS) { 944 LOGERR_((channel->port.info.name.ptr, 945 "Codec unpack() error", status)); 946 /* Just ignore this unpack error */ 947 } 917 } 918 919 if (got_frame) { 920 unsigned i; 921 922 /* Generate frame bitstream from the payload */ 923 channel->buf_len = 0; 924 925 if (cnt > stream->rx_frame_cnt) { 926 PJ_LOG(1,(port->info.name.ptr, 927 "Discarding %u frames because array is full!", 928 cnt - stream->rx_frame_cnt)); 929 pjmedia_jbuf_remove_frame(stream->jb, cnt - stream->rx_frame_cnt); 930 cnt = stream->rx_frame_cnt; 931 } 932 933 for (i = 0; i < cnt; ++i) { 934 char ptype; 935 936 stream->rx_frames[i].type = PJMEDIA_FRAME_TYPE_VIDEO; 937 stream->rx_frames[i].timestamp.u64 = last_ts; 938 stream->rx_frames[i].bit_info = 0; 939 940 /* We use jbuf_peek_frame() as it will returns the pointer of 941 * the payload (no buffer and memcpy needed), just as we need. 942 */ 943 pjmedia_jbuf_peek_frame(stream->jb, i, 944 (const void**)&stream->rx_frames[i].buf, 945 &stream->rx_frames[i].size, &ptype, 946 NULL, NULL, NULL); 947 948 if (ptype != PJMEDIA_JB_NORMAL_FRAME) { 949 /* Packet lost, must set payload to NULL and keep going */ 950 stream->rx_frames[i].buf = NULL; 951 stream->rx_frames[i].size = 0; 952 stream->rx_frames[i].type = PJMEDIA_FRAME_TYPE_NONE; 953 continue; 948 954 } 949 950 pjmedia_jbuf_remove_frame(stream->jb, cnt);951 955 } 952 956 953 /* Unlock jitter buffer mutex. */ 954 pj_mutex_unlock( stream->jb_mutex ); 955 956 if (!got_frame) { 957 /* Decode */ 958 status = pjmedia_vid_codec_decode(stream->codec, cnt, 959 stream->rx_frames, 960 frame->size, frame); 961 if (status != PJ_SUCCESS) { 962 LOGERR_((port->info.name.ptr, "codec decode() error", 963 status)); 957 964 frame->type = PJMEDIA_FRAME_TYPE_NONE; 958 965 frame->size = 0; 959 return PJ_SUCCESS;960 966 } 961 } 962 963 /* Decode */ 964 frame_in.buf = channel->buf; 965 frame_in.size = channel->buf_len; 966 frame_in.bit_info = 0; 967 frame_in.type = PJMEDIA_FRAME_TYPE_VIDEO; 968 frame_in.timestamp.u64 = last_ts; 969 970 status = pjmedia_vid_codec_decode(stream->codec, &frame_in, 971 frame->size, frame); 972 if (status != PJ_SUCCESS) { 973 LOGERR_((port->info.name.ptr, "codec decode() error", 974 status)); 975 frame->type = PJMEDIA_FRAME_TYPE_NONE; 976 frame->size = 0; 977 } 967 968 pjmedia_jbuf_remove_frame(stream->jb, cnt); 969 } 970 971 /* Unlock jitter buffer mutex. */ 972 pj_mutex_unlock( stream->jb_mutex ); 978 973 979 974 /* Learn remote frame rate after successful decoding */ … … 1014 1009 1015 1010 pjmedia_event_init(&event, PJMEDIA_EVENT_FMT_CHANGED, 1016 &frame _in.timestamp, &stream->epub);1011 &frame->timestamp, &stream->epub); 1017 1012 event.data.fmt_changed.dir = PJMEDIA_DIR_DECODING; 1018 1013 pj_memcpy(&event.data.fmt_changed.new_fmt, … … 1157 1152 pjmedia_video_format_detail *vfd_enc; 1158 1153 char *p; 1154 unsigned mtu; 1159 1155 pj_status_t status; 1160 1156 … … 1188 1184 return status; 1189 1185 1190 1191 1186 /* Get codec param: */ 1192 1187 if (!info->codec_param) { … … 1202 1197 pj_assert(info->codec_param); 1203 1198 } 1199 1200 /* Init codec param and adjust MTU */ 1201 info->codec_param->dir = info->dir; 1202 info->codec_param->enc_mtu -= (sizeof(pjmedia_rtp_hdr) + 1203 PJMEDIA_STREAM_RESV_PAYLOAD_LEN); 1204 if (info->codec_param->enc_mtu > PJMEDIA_MAX_MTU) 1205 info->codec_param->enc_mtu = PJMEDIA_MAX_MTU; 1206 mtu = info->codec_param->enc_mtu; 1204 1207 1205 1208 vfd_enc = pjmedia_format_get_video_format_detail( … … 1235 1238 if (status != PJ_SUCCESS) 1236 1239 return status; 1237 1238 /* Init codec param */1239 info->codec_param->dir = info->dir;1240 info->codec_param->enc_mtu = PJMEDIA_MAX_MTU - sizeof(pjmedia_rtp_hdr) -1241 PJMEDIA_STREAM_RESV_PAYLOAD_LEN;1242 1240 1243 1241 /* Init and open the codec. */ … … 1295 1293 /* Init jitter buffer parameters: */ 1296 1294 frm_ptime = 1000 * vfd_enc->fps.denum / vfd_enc->fps.num; 1297 chunks_per_frm = stream->frame_size / PJMEDIA_MAX_MTU; 1295 chunks_per_frm = stream->frame_size / mtu; 1296 if (chunks_per_frm == 0) chunks_per_frm = 1; 1298 1297 1299 1298 /* JB max count, default 500ms */ … … 1321 1320 jb_init = 0; 1322 1321 1322 /* Allocate array for temporary storage for assembly of incoming 1323 * frames. Add more just in case. 1324 */ 1325 stream->rx_frame_cnt = chunks_per_frm * 2; 1326 stream->rx_frames = pj_pool_calloc(pool, stream->rx_frame_cnt, 1327 sizeof(stream->rx_frames[0])); 1328 1323 1329 /* Create jitter buffer */ 1324 1330 status = pjmedia_jbuf_create(pool, &stream->dec->port.info.name, 1325 PJMEDIA_MAX_MTU, 1331 mtu + PJMEDIA_STREAM_RESV_PAYLOAD_LEN, 1326 1332 1000 * vfd_enc->fps.denum / vfd_enc->fps.num, 1327 1333 jb_max, &stream->jb); … … 1461 1467 1462 1468 /* Destroy jitter buffer */ 1463 if (stream->jb) 1469 if (stream->jb) { 1464 1470 pjmedia_jbuf_destroy(stream->jb); 1471 stream->jb = NULL; 1472 } 1465 1473 1466 1474 #if TRACE_JB … … 1708 1716 } 1709 1717 1710 1718 1719 /* Request for codec with the correct packing for streaming */ 1720 si->codec_info.packings = PJMEDIA_VID_PACKING_PACKETS; 1721 1711 1722 /* Now that we have codec info, get the codec param. */ 1712 1723 si->codec_param = PJ_POOL_ALLOC_T(pool, pjmedia_vid_codec_param);
Note: See TracChangeset
for help on using the changeset viewer.