📄 rtp.c
字号:
delta, ch->Jitter >> 4, lost, ch->total_pck, ch->total_bytes )); }#endif //we work with no CSRC so payload offset is always 12 *PayloadStart = 12; //store the time ch->CurrentTime = rtp_hdr->TimeStamp; return e;}GF_EXPORTDouble gf_rtp_get_current_time(GF_RTPChannel *ch){ Double ret; if (!ch) return 0.0; ret = (Double) ch->CurrentTime; ret -= (Double) ch->rtp_time; ret /= ch->TimeScale; return ret;}GF_EXPORTGF_Err gf_rtp_send_packet(GF_RTPChannel *ch, GF_RTPHeader *rtp_hdr, char *extra_header, u32 extra_header_size, char *pck, u32 pck_size){ GF_Err e; u32 Start, i; GF_BitStream *bs; if (!ch || !rtp_hdr || !ch->send_buffer || !pck || (rtp_hdr->CSRCCount && !rtp_hdr->CSRC) || (rtp_hdr->CSRCCount > 15)) return GF_BAD_PARAM; if (12 + extra_header_size + pck_size + 4*rtp_hdr->CSRCCount > ch->send_buffer_size) return GF_IO_ERR; //we don't support multiple CSRC now. Only one source (the server) is allowed if (rtp_hdr->CSRCCount) return GF_NOT_SUPPORTED; bs = gf_bs_new(ch->send_buffer, ch->send_buffer_size, GF_BITSTREAM_WRITE); //write header gf_bs_write_int(bs, rtp_hdr->Version, 2); gf_bs_write_int(bs, rtp_hdr->Padding, 1); gf_bs_write_int(bs, rtp_hdr->Extension, 1); gf_bs_write_int(bs, rtp_hdr->CSRCCount, 4); gf_bs_write_int(bs, rtp_hdr->Marker, 1); gf_bs_write_int(bs, rtp_hdr->PayloadType, 7); gf_bs_write_u16(bs, rtp_hdr->SequenceNumber); gf_bs_write_u32(bs, rtp_hdr->TimeStamp); gf_bs_write_u32(bs, rtp_hdr->SSRC); for (i=0; i<rtp_hdr->CSRCCount; i++) { gf_bs_write_u32(bs, rtp_hdr->CSRC[i]); } //nb: RTP header is always aligned Start = (u32) gf_bs_get_position(bs); gf_bs_del(bs); //extra header if (extra_header_size) { memcpy(ch->send_buffer + Start, extra_header, extra_header_size); Start += extra_header_size; } //payload memcpy(ch->send_buffer + Start, pck, pck_size); e = gf_sk_send(ch->rtp, ch->send_buffer, Start + pck_size); if (e) return e; //Update RTCP for sender reports ch->pck_sent_since_last_sr += 1; if (ch->first_SR) { //get a new report time gf_rtp_get_next_report_time(ch); ch->num_payload_bytes = 0; ch->num_pck_sent = 0; ch->first_SR = 0; } ch->num_payload_bytes += pck_size + extra_header_size; ch->num_pck_sent += 1; //store timing ch->last_pck_ts = rtp_hdr->TimeStamp; gf_net_get_ntp(&ch->last_pck_ntp_sec, &ch->last_pck_ntp_frac); return GF_OK;}GF_EXPORTu32 gf_rtp_is_unicast(GF_RTPChannel *ch){ if (!ch) return 0; return ch->net_info.IsUnicast;}GF_EXPORTu32 gf_rtp_is_interleaved(GF_RTPChannel *ch){ if (!ch || !ch->net_info.Profile) return 0; return ch->net_info.IsInterleaved;}GF_EXPORTu32 gf_rtp_get_clockrate(GF_RTPChannel *ch){ if (!ch || !ch->TimeScale) return 0; return ch->TimeScale;}GF_EXPORTu32 gf_rtp_is_active(GF_RTPChannel *ch){ if (!ch) return 0; if (!ch->rtp_first_SN && !ch->rtp_time) return 0; return 1;}GF_EXPORTu8 gf_rtp_get_low_interleave_id(GF_RTPChannel *ch){ if (!ch || !ch->net_info.IsInterleaved) return 0; return ch->net_info.rtpID;}GF_EXPORTu8 gf_rtp_get_hight_interleave_id(GF_RTPChannel *ch){ if (!ch || !ch->net_info.IsInterleaved) return 0; return ch->net_info.rtcpID;}#define RTP_DEFAULT_FIRSTPORT 7040static u16 NextAvailablePort = 0;GF_EXPORTGF_Err gf_rtp_set_ports(GF_RTPChannel *ch, u16 first_port){ u32 retry; u16 p; GF_Socket *sock; if (!ch) return GF_BAD_PARAM; if (!NextAvailablePort) { NextAvailablePort = first_port ? first_port : RTP_DEFAULT_FIRSTPORT; } p = NextAvailablePort; if (ch->net_info.client_port_first) return GF_OK; sock = gf_sk_new(GF_SOCK_TYPE_UDP); if (!sock) return GF_IO_ERR; /*should be way enough (more than 100 rtp streams open on the machine)*/ retry = 100; while (1) { /*try to bind without reuse. If fails this means the port is used on the machine, don't reuse it*/ GF_Err e = gf_sk_bind(sock, p, NULL, 0, 0); if (e==GF_OK) break; if (e!=GF_IP_CONNECTION_FAILURE) { gf_sk_del(sock); return GF_IP_NETWORK_FAILURE; } p+=2; } gf_sk_del(sock); ch->net_info.client_port_first = p; ch->net_info.client_port_last = p + 1; NextAvailablePort = p + 2; return GF_OK;}GF_EXPORTGF_Err gf_rtp_setup_payload(GF_RTPChannel *ch, GF_RTPMap *map){ if (!ch || !map) return GF_BAD_PARAM; ch->PayloadType = map->PayloadType; ch->TimeScale = map->ClockRate; return GF_OK;}GF_EXPORTGF_RTSPTransport *gf_rtp_get_transport(GF_RTPChannel *ch){ if (!ch) return NULL; return &ch->net_info;}GF_EXPORTu32 gf_rtp_get_local_ssrc(GF_RTPChannel *ch){ if (!ch) return 0; return ch->SSRC;}#if 0 "#RTP log format:\n" "#RTP SenderSSRC RTP_TimeStamp RTP_SeqNum NTP@Recv Deviance Jitter NbLost NbTotPck NbTotBytes\n" "#RTCP Sender reports log format:\n" "#RTCP-SR SenderSSRC RTP_TimeStamp@NTP NbTotPck NbTotBytes NTP\n" "#RTCP Receiver reports log format:\n" "#RTCP-RR StreamSSRC Jitter ExtendedSeqNum ExpectDiff LossDiff NTP\n"#endifGF_EXPORTFloat gf_rtp_get_loss(GF_RTPChannel *ch){ if (!ch->tot_num_pck_expected) return 0.0f; return 100.0f - (100.0f * ch->tot_num_pck_rcv) / ch->tot_num_pck_expected;}GF_EXPORTu32 gf_rtp_get_tcp_bytes_sent(GF_RTPChannel *ch){ return ch->rtcp_bytes_sent;}GF_EXPORTvoid gf_rtp_get_ports(GF_RTPChannel *ch, u16 *rtp_port, u16 *rtcp_port){ *rtp_port = ch->net_info.client_port_first; *rtcp_port = ch->net_info.client_port_last;}/* RTP packet reorderer*/#define SN_CHECK_OFFSET 0x0AGF_RTPReorder *gf_rtp_reorderer_new(u32 MaxCount, u32 MaxDelay){ GF_RTPReorder *tmp; if (MaxCount <= 1 || !MaxDelay) return NULL; GF_SAFEALLOC(tmp , GF_RTPReorder); tmp->MaxCount = MaxCount; tmp->MaxDelay = MaxDelay; return tmp;}static void DelItem(GF_POItem *it){ if (it) { if (it->next) DelItem(it->next); free(it->pck); free(it); }}void gf_rtp_reorderer_del(GF_RTPReorder *po){ if (po->in) DelItem(po->in); free(po);}void gf_rtp_reorderer_reset(GF_RTPReorder *po){ if (!po) return; if (po->in) DelItem(po->in); po->head_seqnum = 0; po->Count = 0; po->IsInit = 0; po->in = NULL;}GF_Err gf_rtp_reorderer_add(GF_RTPReorder *po, void *pck, u32 pck_size, u32 pck_seqnum){ GF_POItem *it, *cur; u32 bounds; if (!po) return GF_BAD_PARAM; it = (GF_POItem *) malloc(sizeof(GF_POItem)); it->pck_seq_num = pck_seqnum; it->next = NULL; it->size = pck_size; it->pck = malloc(pck_size); memcpy(it->pck, pck, pck_size); /*reset timeout*/ po->LastTime = 0; //no input, this packet will be the input if (!po->in) { //the seq num was not initialized if (!po->head_seqnum) { po->head_seqnum = pck_seqnum; } else if (!po->IsInit) { //this is not in our current range for init if (ABSDIFF(po->head_seqnum, pck_seqnum) > SN_CHECK_OFFSET) goto discard; po->IsInit = 1; } po->in = it; po->Count += 1; return GF_OK; } //this is 16 bitr seq num, as we work with RTP only for now bounds = 0; if ( (po->head_seqnum >= 0xf000 ) || (po->head_seqnum <= 0x1000) ) bounds = 0x2000; //first check the head of the list //same seq num, we drop if (po->in->pck_seq_num == pck_seqnum) goto discard; if ( ( (u16) (pck_seqnum + bounds) <= (u16) (po->in->pck_seq_num + bounds) ) && ( (u16) (pck_seqnum + bounds) >= (u16) (po->head_seqnum + bounds)) ) { it->next = po->in; po->in = it; po->Count += 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: inserting packet %d at head\n", pck_seqnum)); return GF_OK; } //no, insert at the right place cur = po->in; while (1) { //same seq num, we drop if (cur->pck_seq_num == pck_seqnum) goto discard; //end of list if (!cur->next) { cur->next = it; po->Count += 1;#ifndef GPAC_DISABLE_LOG if (cur->pck_seq_num +1 != it->pck_seq_num) GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[rtp] Packet Reorderer: got %d expected %d\n", cur->pck_seq_num+1, it->pck_seq_num)); GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: Appending packet %d\n", pck_seqnum));#endif return GF_OK; } //are we in the bounds ?? if ( ( (u16) (cur->pck_seq_num + bounds) < (u16) (pck_seqnum + bounds) ) && ( (u16) (pck_seqnum + bounds) < (u16) (cur->next->pck_seq_num + bounds)) ) { //insert it->next = cur->next; cur->next = it; po->Count += 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: Inserting packet %d", pck_seqnum)); //done return GF_OK; } cur = cur->next; } discard: free(it->pck); free(it); GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[rtp] Packet Reorderer: Dropping packet %d", pck_seqnum)); return GF_OK;}//retrieve the first available packet. Note that the behavior will be undefined if the first//ever recieved packet if its SeqNum was unknown//the BUFFER is yours, you must delete itvoid *gf_rtp_reorderer_get(GF_RTPReorder *po, u32 *pck_size){ GF_POItem *t; u32 bounds; void *ret; if (!po || !pck_size) return NULL; *pck_size = 0; //empty queue if (!po->in) return NULL; //check we have recieved the first packet if ( po->head_seqnum && po->MaxCount && (po->MaxCount > po->Count) && (po->in->pck_seq_num != po->head_seqnum)) return NULL; //no entry if (!po->in->next) goto check_timeout; bounds = 0; if ( (po->head_seqnum >= 0xf000 ) || (po->head_seqnum <= 0x1000) ) bounds = 0x2000; //release the output if SN in order or maxCount reached if (( (u16) (po->in->pck_seq_num + bounds + 1) == (u16) (po->in->next->pck_seq_num + bounds)) || (po->MaxCount && po->Count == po->MaxCount) ) {#ifndef GPAC_DISABLE_LOG if (po->in->pck_seq_num + 1 != po->in->next->pck_seq_num) GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[rtp] Packet Reorderer: Fetched %d expected %d\n", po->in->pck_seq_num, po->in->next->pck_seq_num));#endif goto send_it; } //update timing else {check_timeout: if (!po->LastTime) { po->LastTime = gf_sys_clock(); GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: starting timeout at %d\n", po->LastTime)); return NULL; } //if exceeding the delay send the head if (gf_sys_clock() - po->LastTime >= po->MaxDelay) { GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: Forcing output after %d ms wait (max allowed %d)\n", gf_sys_clock() - po->LastTime, po->MaxDelay)); goto send_it; } } return NULL;send_it: GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[rtp] Packet Reorderer: Fetching %d\n", po->in->pck_seq_num)); *pck_size = po->in->size; t = po->in; po->in = po->in->next; //no other output. reset the head seqnum po->head_seqnum = po->in ? po->in->pck_seq_num : 0; po->Count -= 1; //release the item ret = t->pck; free(t); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -